tzsetup.c revision 22181
119872Swollman/* 219872Swollman * Copyright 1996 Massachusetts Institute of Technology 319872Swollman * 419872Swollman * Permission to use, copy, modify, and distribute this software and 519872Swollman * its documentation for any purpose and without fee is hereby 619872Swollman * granted, provided that both the above copyright notice and this 719872Swollman * permission notice appear in all copies, that both the above 819872Swollman * copyright notice and this permission notice appear in all 919872Swollman * supporting documentation, and that the name of M.I.T. not be used 1019872Swollman * in advertising or publicity pertaining to distribution of the 1119872Swollman * software without specific, written prior permission. M.I.T. makes 1219872Swollman * no representations about the suitability of this software for any 1319872Swollman * purpose. It is provided "as is" without express or implied 1419872Swollman * warranty. 1519872Swollman * 1619872Swollman * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1719872Swollman * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1819872Swollman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1919872Swollman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2019872Swollman * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2119872Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2219872Swollman * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2319872Swollman * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2419872Swollman * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2519872Swollman * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2619872Swollman * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2719872Swollman * SUCH DAMAGE. 2819872Swollman * 2921673Sjkh * $FreeBSD: head/usr.sbin/tzsetup/tzsetup.c 22181 1997-02-01 17:03:10Z jhay $ 3019872Swollman */ 3119872Swollman 3219872Swollman/* 3319872Swollman * Second attempt at a `tzmenu' program, using the separate description 3419872Swollman * files provided in newer tzdata releases. 3519872Swollman */ 3619872Swollman 3719872Swollman#include <sys/types.h> 3819872Swollman#include <dialog.h> 3919872Swollman#include <err.h> 4019872Swollman#include <errno.h> 4119872Swollman#include <stdio.h> 4219872Swollman#include <stdlib.h> 4319872Swollman#include <string.h> 4419872Swollman#include <unistd.h> 4519872Swollman 4619872Swollman#include <sys/fcntl.h> 4719872Swollman#include <sys/queue.h> 4819872Swollman#include <sys/stat.h> 4919872Swollman 5019872Swollman#include "paths.h" 5119872Swollman 5219872Swollmanstatic int reallydoit = 1; 5319872Swollman 5419872Swollmanstatic int continent_country_menu(dialogMenuItem *); 5519872Swollmanstatic int set_zone_multi(dialogMenuItem *); 5619872Swollmanstatic int set_zone_whole_country(dialogMenuItem *); 5719872Swollmanstatic int set_zone_menu(dialogMenuItem *); 5819872Swollman 5919872Swollmanstruct continent { 6019872Swollman dialogMenuItem *menu; 6119872Swollman int nitems; 6219872Swollman int ch; 6319872Swollman int sc; 6419872Swollman}; 6519872Swollman 6619872Swollmanstatic struct continent africa, america, antarctica, arctic, asia, atlantic; 6719872Swollmanstatic struct continent australia, europe, indian, pacific; 6819872Swollman 6919872Swollmanstatic struct continent_names { 7019872Swollman char *name; 7119872Swollman struct continent *continent; 7219872Swollman} continent_names[] = { 7319872Swollman { "Africa", &africa }, { "America", &america }, 7419872Swollman { "Antarctica", &antarctica }, { "Arctic", &arctic }, 7519872Swollman { "Asia", &asia }, 7619872Swollman { "Atlantic", &atlantic }, { "Australia", &australia }, 7719872Swollman { "Europe", &europe }, { "Indian", &indian }, { "Pacific", &pacific } 7819872Swollman}; 7919872Swollman 8019872Swollmanstatic dialogMenuItem continents[] = { 8119872Swollman { "1", "Africa", 0, continent_country_menu, 0, &africa }, 8219872Swollman { "2", "America -- North and South", 0, continent_country_menu, 0, 8319872Swollman &america }, 8419872Swollman { "3", "Antarctica", 0, continent_country_menu, 0, &antarctica }, 8519872Swollman { "4", "Arctic Ocean", 0, continent_country_menu, 0, &arctic }, 8619872Swollman { "5", "Asia", 0, continent_country_menu, 0, &asia }, 8719872Swollman { "6", "Atlantic Ocean", 0, continent_country_menu, 0, &atlantic }, 8819872Swollman { "7", "Australia", 0, continent_country_menu, 0, &australia }, 8919872Swollman { "8", "Europe", 0, continent_country_menu, 0, &europe }, 9019872Swollman { "9", "Indian Ocean", 0, continent_country_menu, 0, &indian }, 9119872Swollman { "0", "Pacific Ocean", 0, continent_country_menu, 0, &pacific } 9219872Swollman}; 9319872Swollman#define NCONTINENTS ((sizeof continents)/(sizeof continents[0])) 9419872Swollman#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) 9519872Swollman 9619872Swollmanstatic int 9719872Swollmancontinent_country_menu(dialogMenuItem *continent) 9819872Swollman{ 9919872Swollman int rv; 10019872Swollman struct continent *contp = continent->data; 10119872Swollman char title[256]; 10219872Swollman int isocean = OCEANP(continent - continents); 10319872Swollman int menulen; 10419872Swollman 10519872Swollman /* Short cut -- if there's only one country, don't post a menu. */ 10619872Swollman if (contp->nitems == 1) { 10719872Swollman return set_zone_menu(&contp->menu[0]); 10819872Swollman } 10919872Swollman 11019872Swollman /* It's amazing how much good grammar really matters... */ 11119872Swollman if (!isocean) 11219872Swollman snprintf(title, sizeof title, "Countries in %s", 11319872Swollman continent->title); 11419872Swollman else 11519872Swollman snprintf(title, sizeof title, "Islands and groups in the %s", 11619872Swollman continent->title); 11719872Swollman 11819872Swollman menulen = contp->nitems < 16 ? contp->nitems : 16; 11919872Swollman rv = dialog_menu(title, (isocean ? "Select an island or group" 12019872Swollman : "Select a country"), -1, -1, menulen, 12119872Swollman -contp->nitems, contp->menu, 0, &contp->ch, 12219872Swollman &contp->sc); 12319872Swollman if (rv == 0) 12419872Swollman return DITEM_LEAVE_MENU; 12519872Swollman return DITEM_RECREATE; 12619872Swollman} 12719872Swollman 12819872Swollmanstatic struct continent * 12919872Swollmanfind_continent(const char *name) 13019872Swollman{ 13119872Swollman int i; 13219872Swollman 13319872Swollman for (i = 0; i < NCONTINENTS; i++) { 13419872Swollman if (strcmp(name, continent_names[i].name) == 0) 13519872Swollman return continent_names[i].continent; 13619872Swollman } 13719872Swollman return 0; 13819872Swollman} 13919872Swollman 14019872Swollmanstruct country { 14119872Swollman char *name; 14219872Swollman char *tlc; 14319872Swollman int nzones; 14419872Swollman char *filename; /* use iff nzones < 0 */ 14519872Swollman struct continent *continent; /* use iff nzones < 0 */ 14619872Swollman TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ 14719872Swollman dialogMenuItem *submenu; /* use iff nzones > 0 */ 14819872Swollman}; 14919872Swollman 15019872Swollmanstruct zone { 15119872Swollman TAILQ_ENTRY(zone) link; 15219872Swollman char *descr; 15319872Swollman char *filename; 15419872Swollman struct continent *continent; 15519872Swollman}; 15619872Swollman 15719872Swollman/* 15819872Swollman * This is the easiest organization... we use ISO 3166 country codes, 15919872Swollman * of the two-letter variety, so we just size this array to suit. 16019872Swollman * Beats worrying about dynamic allocation. 16119872Swollman */ 16222181Sjhay#define NCOUNTRIES (26*26) 16322181Sjhaystatic struct country countries[NCOUNTRIES]; 16419872Swollman#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 16519872Swollman 16619872Swollman/* 16719872Swollman * Read the ISO 3166 country code database in _PATH_ISO3166 16819872Swollman * (/usr/share/misc/iso3166). On error, exit via err(3). 16919872Swollman */ 17019872Swollmanstatic void 17119872Swollmanread_iso3166_table(void) 17219872Swollman{ 17319872Swollman FILE *fp; 17419872Swollman char *s, *t, *name; 17519872Swollman size_t len; 17619872Swollman int lineno; 17719872Swollman struct country *cp; 17819872Swollman 17919872Swollman fp = fopen(_PATH_ISO3166, "r"); 18019872Swollman if (!fp) 18119872Swollman err(1, _PATH_ISO3166); 18219872Swollman lineno = 0; 18319872Swollman 18419872Swollman while ((s = fgetln(fp, &len)) != 0) { 18519872Swollman lineno++; 18619872Swollman if (s[len - 1] != '\n') 18719872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 18819872Swollman s[len - 1] = '\0'; 18919872Swollman if (s[0] == '#') 19019872Swollman continue; 19119872Swollman 19219872Swollman /* Isolate the two-letter code. */ 19319872Swollman t = strsep(&s, "\t"); 19419872Swollman if (t == 0 || strlen(t) != 2) 19519872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 19619872Swollman if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 19719872Swollman errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", 19819872Swollman lineno, t); 19919872Swollman 20019872Swollman /* Now skip past the three-letter and numeric codes. */ 20119872Swollman name = strsep(&s, "\t"); /* 3-let */ 20219872Swollman if (name == 0 || strlen(name) != 3) 20319872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20419872Swollman name = strsep(&s, "\t"); /* numeric */ 20519872Swollman if (name == 0 || strlen(name) != 3) 20619872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20719872Swollman 20819872Swollman name = s; 20919872Swollman 21019872Swollman cp = &countries[CODE2INT(t)]; 21119872Swollman if (cp->name) 21219872Swollman errx(1, _PATH_ISO3166 21319872Swollman ":%d: country code `%s' multiply defined: %s", 21419872Swollman lineno, t, cp->name); 21519872Swollman cp->name = strdup(name); 21619872Swollman cp->tlc = strdup(t); 21719872Swollman } 21819872Swollman 21919872Swollman fclose(fp); 22019872Swollman} 22119872Swollman 22219872Swollmanstatic void 22319872Swollmanadd_zone_to_country(int lineno, const char *tlc, const char *descr, 22419872Swollman const char *file, struct continent *cont) 22519872Swollman{ 22619872Swollman struct zone *zp; 22719872Swollman struct country *cp; 22819872Swollman 22919872Swollman if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 23019872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", 23119872Swollman lineno, tlc); 23219872Swollman 23319872Swollman cp = &countries[CODE2INT(tlc)]; 23419872Swollman if (cp->name == 0) 23519872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", 23619872Swollman lineno, tlc); 23719872Swollman 23819872Swollman if (descr) { 23919872Swollman if (cp->nzones < 0) 24019872Swollman errx(1, _PATH_ZONETAB 24119872Swollman ":%d: conflicting zone definition", lineno); 24219872Swollman 24319872Swollman zp = malloc(sizeof *zp); 24419872Swollman if (zp == 0) 24519872Swollman err(1, "malloc(%lu)", (unsigned long)sizeof *zp); 24619872Swollman 24719872Swollman if (cp->nzones == 0) 24819872Swollman TAILQ_INIT(&cp->zones); 24919872Swollman 25019872Swollman zp->descr = strdup(descr); 25119872Swollman zp->filename = strdup(file); 25219872Swollman zp->continent = cont; 25319872Swollman TAILQ_INSERT_TAIL(&cp->zones, zp, link); 25419872Swollman cp->nzones++; 25519872Swollman } else { 25619872Swollman if (cp->nzones > 0) 25719872Swollman errx(1, _PATH_ZONETAB 25819872Swollman ":%d: zone must have description", lineno); 25919872Swollman if (cp->nzones < 0) 26019872Swollman errx(1, _PATH_ZONETAB 26119872Swollman ":%d: zone multiply defined", lineno); 26219872Swollman cp->nzones = -1; 26319872Swollman cp->filename = strdup(file); 26419872Swollman cp->continent = cont; 26519872Swollman } 26619872Swollman} 26719872Swollman 26819872Swollman/* 26919872Swollman * This comparison function intentionally sorts all of the null-named 27019872Swollman * ``countries''---i.e., the codes that don't correspond to a real 27119872Swollman * country---to the end. Everything else is lexical by country name. 27219872Swollman */ 27319872Swollmanstatic int 27419872Swollmancompare_countries(const void *xa, const void *xb) 27519872Swollman{ 27619872Swollman const struct country *a = xa, *b = xb; 27719872Swollman 27819872Swollman if (a->name == 0 && b->name == 0) 27919872Swollman return 0; 28019872Swollman if (a->name == 0 && b->name != 0) 28119872Swollman return 1; 28219872Swollman if (b->name == 0) 28319872Swollman return -1; 28419872Swollman 28519872Swollman return strcmp(a->name, b->name); 28619872Swollman} 28719872Swollman 28819872Swollman/* 28919872Swollman * This must be done AFTER all zone descriptions are read, since it breaks 29019872Swollman * CODE2INT(). 29119872Swollman */ 29219872Swollmanstatic void 29319872Swollmansort_countries(void) 29419872Swollman{ 29522181Sjhay qsort(countries, NCOUNTRIES, sizeof countries[0], compare_countries); 29619872Swollman} 29719872Swollman 29819872Swollmanstatic void 29919872Swollmanread_zones(void) 30019872Swollman{ 30119872Swollman FILE *fp; 30219872Swollman char *line; 30319872Swollman size_t len; 30419872Swollman int lineno; 30519872Swollman char *tlc, *coord, *file, *descr, *p; 30619872Swollman char contbuf[16]; 30719872Swollman struct continent *cont; 30819872Swollman 30919872Swollman fp = fopen(_PATH_ZONETAB, "r"); 31019872Swollman if (!fp) 31119872Swollman err(1, _PATH_ZONETAB); 31219872Swollman lineno = 0; 31319872Swollman 31419872Swollman while ((line = fgetln(fp, &len)) != 0) { 31519872Swollman lineno++; 31619872Swollman if (line[len - 1] != '\n') 31719872Swollman errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); 31819872Swollman line[len - 1] = '\0'; 31919872Swollman if (line[0] == '#') 32019872Swollman continue; 32119872Swollman 32219872Swollman tlc = strsep(&line, "\t"); 32319872Swollman if (strlen(tlc) != 2) 32419872Swollman errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", 32519872Swollman lineno, tlc); 32619872Swollman coord = strsep(&line, "\t"); 32719872Swollman file = strsep(&line, "\t"); 32819872Swollman p = strchr(file, '/'); 32919872Swollman if (p == 0) 33019872Swollman errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", 33119872Swollman lineno, file); 33219872Swollman contbuf[0] = '\0'; 33319872Swollman strncat(contbuf, file, p - file); 33419872Swollman cont = find_continent(contbuf); 33519872Swollman if (!cont) 33619872Swollman errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", 33719872Swollman lineno, contbuf); 33819872Swollman 33919872Swollman descr = (line && *line) ? line : 0; 34019872Swollman 34119872Swollman add_zone_to_country(lineno, tlc, descr, file, cont); 34219872Swollman } 34319872Swollman fclose(fp); 34419872Swollman} 34519872Swollman 34619872Swollmanstatic void 34719872Swollmanmake_menus(void) 34819872Swollman{ 34919872Swollman struct country *cp; 35019872Swollman struct zone *zp, *zp2; 35119872Swollman struct continent *cont; 35219872Swollman dialogMenuItem *dmi; 35319872Swollman int i; 35419872Swollman 35519872Swollman /* 35619872Swollman * First, count up all the countries in each continent/ocean. 35719872Swollman * Be careful to count those countries which have multiple zones 35819872Swollman * only once for each. NB: some countries are in multiple 35919872Swollman * continents/oceans. 36019872Swollman */ 36119872Swollman for (cp = countries; cp->name; cp++) { 36219872Swollman if (cp->nzones == 0) 36319872Swollman continue; 36419872Swollman if (cp->nzones < 0) { 36519872Swollman cp->continent->nitems++; 36619872Swollman } else { 36719872Swollman for (zp = cp->zones.tqh_first; zp; 36819872Swollman zp = zp->link.tqe_next) { 36919872Swollman cont = zp->continent; 37019872Swollman for (zp2 = cp->zones.tqh_first; 37119872Swollman zp2->continent != cont; 37219872Swollman zp2 = zp2->link.tqe_next) 37319872Swollman ; 37419872Swollman if (zp2 == zp) 37519872Swollman zp->continent->nitems++; 37619872Swollman } 37719872Swollman } 37819872Swollman } 37919872Swollman 38019872Swollman /* 38119872Swollman * Now allocate memory for the country menus. We set 38219872Swollman * nitems back to zero so that we can use it for counting 38319872Swollman * again when we actually build the menus. 38419872Swollman */ 38519872Swollman for (i = 0; i < NCONTINENTS; i++) { 38619872Swollman continent_names[i].continent->menu = 38719872Swollman malloc(sizeof(dialogMenuItem) * 38819872Swollman continent_names[i].continent->nitems); 38919872Swollman if (continent_names[i].continent->menu == 0) 39019872Swollman err(1, "malloc for continent menu"); 39119872Swollman continent_names[i].continent->nitems = 0; 39219872Swollman } 39319872Swollman 39419872Swollman /* 39519872Swollman * Now that memory is allocated, create the menu items for 39619872Swollman * each continent. For multiple-zone countries, also create 39719872Swollman * the country's zone submenu. 39819872Swollman */ 39919872Swollman for (cp = countries; cp->name; cp++) { 40019872Swollman if (cp->nzones == 0) 40119872Swollman continue; 40219872Swollman if (cp->nzones < 0) { 40319872Swollman dmi = &cp->continent->menu[cp->continent->nitems]; 40419872Swollman memset(dmi, 0, sizeof *dmi); 40519872Swollman asprintf(&dmi->prompt, "%d", 40619872Swollman ++cp->continent->nitems); 40719872Swollman dmi->title = cp->name; 40819872Swollman dmi->checked = 0; 40919872Swollman dmi->fire = set_zone_whole_country; 41019872Swollman dmi->selected = 0; 41119872Swollman dmi->data = cp; 41219872Swollman } else { 41319872Swollman cp->submenu = malloc(cp->nzones * sizeof *dmi); 41419872Swollman if (cp->submenu == 0) 41519872Swollman err(1, "malloc for submenu"); 41619872Swollman cp->nzones = 0; 41719872Swollman for (zp = cp->zones.tqh_first; zp; 41819872Swollman zp = zp->link.tqe_next) { 41919872Swollman cont = zp->continent; 42019872Swollman dmi = &cp->submenu[cp->nzones]; 42119872Swollman memset(dmi, 0, sizeof *dmi); 42219872Swollman asprintf(&dmi->prompt, "%d", 42319872Swollman ++cp->nzones); 42419872Swollman dmi->title = zp->descr; 42519872Swollman dmi->checked = 0; 42619872Swollman dmi->fire = set_zone_multi; 42719872Swollman dmi->selected = 0; 42819872Swollman dmi->data = zp; 42919872Swollman 43019872Swollman for (zp2 = cp->zones.tqh_first; 43119872Swollman zp2->continent != cont; 43219872Swollman zp2 = zp2->link.tqe_next) 43319872Swollman ; 43419872Swollman if (zp2 != zp) 43519872Swollman continue; 43619872Swollman 43719872Swollman dmi = &cont->menu[cont->nitems]; 43819872Swollman memset(dmi, 0, sizeof *dmi); 43919872Swollman asprintf(&dmi->prompt, "%d", ++cont->nitems); 44019872Swollman dmi->title = cp->name; 44119872Swollman dmi->checked = 0; 44219872Swollman dmi->fire = set_zone_menu; 44319872Swollman dmi->selected = 0; 44419872Swollman dmi->data = cp; 44519872Swollman } 44619872Swollman } 44719872Swollman } 44819872Swollman} 44919872Swollman 45019872Swollmanstatic int 45119872Swollmanset_zone_menu(dialogMenuItem *dmi) 45219872Swollman{ 45319872Swollman int rv; 45419872Swollman char buf[256]; 45519872Swollman struct country *cp = dmi->data; 45619872Swollman int menulen; 45719872Swollman 45819872Swollman snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 45919872Swollman menulen = cp->nzones < 16 ? cp->nzones : 16; 46019872Swollman rv = dialog_menu(buf, "Select a zone which observes the same time as " 46119872Swollman "your locality.", -1, -1, menulen, -cp->nzones, 46219872Swollman cp->submenu, 0, 0, 0); 46319872Swollman if (rv != 0) 46419872Swollman return DITEM_RECREATE; 46519872Swollman return DITEM_LEAVE_MENU; 46619872Swollman} 46719872Swollman 46819872Swollmanstatic int 46919872Swollmaninstall_zone_file(const char *filename) 47019872Swollman{ 47119872Swollman struct stat sb; 47219872Swollman int fd1, fd2; 47319872Swollman int copymode; 47419872Swollman char *msg; 47519872Swollman ssize_t len; 47619872Swollman char buf[1024]; 47719872Swollman 47819872Swollman if (lstat(_PATH_LOCALTIME, &sb) < 0) 47919872Swollman /* Nothing there yet... */ 48019872Swollman copymode = 1; 48119872Swollman else if(S_ISLNK(sb.st_mode)) 48219872Swollman copymode = 0; 48319872Swollman else 48419872Swollman copymode = 1; 48519872Swollman 48621915Sjkh#ifdef VERBOSE 48719872Swollman if (copymode) 48819872Swollman asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 48919872Swollman else 49019872Swollman asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 49119872Swollman " to %s", filename); 49219872Swollman 49319872Swollman dialog_notify(msg); 49419872Swollman free(msg); 49521915Sjkh#endif 49619872Swollman 49719872Swollman if (reallydoit) { 49819872Swollman if (copymode) { 49919872Swollman fd1 = open(filename, O_RDONLY, 0); 50019872Swollman if (fd1 < 0) { 50119872Swollman asprintf(&msg, "Could not open %s: %s", 50219872Swollman filename, strerror(errno)); 50319872Swollman dialog_mesgbox("Error", msg, 8, 72); 50419872Swollman free(msg); 50519872Swollman return DITEM_FAILURE | DITEM_RECREATE; 50619872Swollman } 50719872Swollman 50819872Swollman unlink(_PATH_LOCALTIME); 50919872Swollman fd2 = open(_PATH_LOCALTIME, 51019872Swollman O_CREAT | O_EXCL | O_WRONLY, 51119872Swollman 0444); 51219872Swollman if (fd2 < 0) { 51319872Swollman asprintf(&msg, "Could not open " 51419872Swollman _PATH_LOCALTIME ": %s", 51519872Swollman strerror(errno)); 51619872Swollman dialog_mesgbox("Error", msg, 8, 72); 51719872Swollman free(msg); 51819872Swollman return DITEM_FAILURE | DITEM_RECREATE; 51919872Swollman } 52019872Swollman 52119872Swollman while ((len = read(fd1, buf, sizeof buf)) > 0) 52219872Swollman len = write(fd2, buf, len); 52319872Swollman 52419872Swollman if (len == -1) { 52519872Swollman asprintf(&msg, "Error copying %s to " 52619872Swollman _PATH_LOCALTIME ": %s", 52719872Swollman strerror(errno)); 52819872Swollman dialog_mesgbox("Error", msg, 8, 72); 52919872Swollman free(msg); 53019872Swollman /* Better to leave none than a corrupt one. */ 53119872Swollman unlink(_PATH_LOCALTIME); 53219872Swollman return DITEM_FAILURE | DITEM_RECREATE; 53319872Swollman } 53419872Swollman close(fd1); 53519872Swollman close(fd2); 53619872Swollman } else { 53719872Swollman if (access(filename, R_OK) != 0) { 53819872Swollman asprintf(&msg, "Cannot access %s: %s", 53919872Swollman filename, strerror(errno)); 54019872Swollman dialog_mesgbox("Error", msg, 8, 72); 54119872Swollman free(msg); 54219872Swollman return DITEM_FAILURE | DITEM_RECREATE; 54319872Swollman } 54419872Swollman unlink(_PATH_LOCALTIME); 54519872Swollman if (symlink(filename, _PATH_LOCALTIME) < 0) { 54619872Swollman asprintf(&msg, "Cannot create symbolic link " 54719872Swollman _PATH_LOCALTIME " to %s: %s", 54819872Swollman filename, strerror(errno)); 54919872Swollman dialog_mesgbox("Error", msg, 8, 72); 55019872Swollman free(msg); 55119872Swollman return DITEM_FAILURE | DITEM_RECREATE; 55219872Swollman } 55319872Swollman } 55419872Swollman } 55519872Swollman 55621915Sjkh#ifdef VERBOSE 55719872Swollman if (copymode) 55819872Swollman asprintf(&msg, "Copied timezone file from %s to " 55919872Swollman _PATH_LOCALTIME, filename); 56019872Swollman else 56119872Swollman asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 56219872Swollman " to %s", filename); 56319872Swollman 56419872Swollman dialog_mesgbox("Done", msg, 8, 72); 56519872Swollman free(msg); 56621915Sjkh#endif 56719872Swollman return DITEM_LEAVE_MENU; 56819872Swollman} 56919872Swollman 57019872Swollmanstatic int 57119872Swollmanconfirm_zone(const char *filename) 57219872Swollman{ 57319872Swollman char *msg; 57419872Swollman struct tm *tm; 57519872Swollman time_t t = time(0); 57619872Swollman int rv; 57719872Swollman 57819872Swollman setenv("TZ", filename, 1); 57919872Swollman tzset(); 58019872Swollman tm = localtime(&t); 58119872Swollman 58219872Swollman asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 58319872Swollman tm->tm_zone); 58419872Swollman rv = !dialog_yesno("Confirmation", msg, 4, 72); 58519872Swollman free(msg); 58619872Swollman return rv; 58719872Swollman} 58819872Swollman 58919872Swollmanstatic int 59019872Swollmanset_zone_multi(dialogMenuItem *dmi) 59119872Swollman{ 59219872Swollman char *fn; 59319872Swollman struct zone *zp = dmi->data; 59419872Swollman int rv; 59519872Swollman 59619872Swollman if (!confirm_zone(zp->filename)) 59719872Swollman return DITEM_FAILURE | DITEM_RECREATE; 59819872Swollman 59919872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 60019872Swollman rv = install_zone_file(fn); 60119872Swollman free(fn); 60219872Swollman return rv; 60319872Swollman} 60419872Swollman 60519872Swollmanstatic int 60619872Swollmanset_zone_whole_country(dialogMenuItem *dmi) 60719872Swollman{ 60819872Swollman char *fn; 60919872Swollman struct country *cp = dmi->data; 61019872Swollman int rv; 61119872Swollman 61219872Swollman if (!confirm_zone(cp->filename)) 61319872Swollman return DITEM_FAILURE | DITEM_RECREATE; 61419872Swollman 61519872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 61619872Swollman rv = install_zone_file(fn); 61719872Swollman free(fn); 61819872Swollman return rv; 61919872Swollman} 62019872Swollman 62119872Swollmanint 62219872Swollmanmain(int argc, char **argv) 62319872Swollman{ 62419872Swollman int c; 62519872Swollman 62619872Swollman while ((c = getopt(argc, argv, "n")) != -1) { 62719872Swollman switch(c) { 62819872Swollman case 'n': 62919872Swollman reallydoit = 0; 63019872Swollman break; 63119872Swollman 63219872Swollman default: 63319872Swollman fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], 63419872Swollman argv[0]); 63519872Swollman exit(1); 63619872Swollman } 63719872Swollman } 63819872Swollman 63919872Swollman if (optind != argc) { 64019872Swollman fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], argv[0]); 64119872Swollman exit(1); 64219872Swollman } 64319872Swollman 64419872Swollman read_iso3166_table(); 64519872Swollman read_zones(); 64619872Swollman sort_countries(); 64719872Swollman make_menus(); 64819872Swollman 64919872Swollman init_dialog(); 65019872Swollman dialog_menu("Time Zone Selector", "Select a region", -1, -1, 65119887Sjoerg NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 65219872Swollman end_dialog(); 65319872Swollman return 0; 65419872Swollman} 65519872Swollman 656