tzsetup.c revision 21673
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 21673 1997-01-14 07:20:47Z jkh $ 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 */ 16219872Swollmanstatic struct country countries[26*26]; 16319872Swollman#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 16419872Swollman 16519872Swollman/* 16619872Swollman * Read the ISO 3166 country code database in _PATH_ISO3166 16719872Swollman * (/usr/share/misc/iso3166). On error, exit via err(3). 16819872Swollman */ 16919872Swollmanstatic void 17019872Swollmanread_iso3166_table(void) 17119872Swollman{ 17219872Swollman FILE *fp; 17319872Swollman char *s, *t, *name; 17419872Swollman size_t len; 17519872Swollman int lineno; 17619872Swollman struct country *cp; 17719872Swollman 17819872Swollman fp = fopen(_PATH_ISO3166, "r"); 17919872Swollman if (!fp) 18019872Swollman err(1, _PATH_ISO3166); 18119872Swollman lineno = 0; 18219872Swollman 18319872Swollman while ((s = fgetln(fp, &len)) != 0) { 18419872Swollman lineno++; 18519872Swollman if (s[len - 1] != '\n') 18619872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 18719872Swollman s[len - 1] = '\0'; 18819872Swollman if (s[0] == '#') 18919872Swollman continue; 19019872Swollman 19119872Swollman /* Isolate the two-letter code. */ 19219872Swollman t = strsep(&s, "\t"); 19319872Swollman if (t == 0 || strlen(t) != 2) 19419872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 19519872Swollman if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 19619872Swollman errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", 19719872Swollman lineno, t); 19819872Swollman 19919872Swollman /* Now skip past the three-letter and numeric codes. */ 20019872Swollman name = strsep(&s, "\t"); /* 3-let */ 20119872Swollman if (name == 0 || strlen(name) != 3) 20219872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20319872Swollman name = strsep(&s, "\t"); /* numeric */ 20419872Swollman if (name == 0 || strlen(name) != 3) 20519872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20619872Swollman 20719872Swollman name = s; 20819872Swollman 20919872Swollman cp = &countries[CODE2INT(t)]; 21019872Swollman if (cp->name) 21119872Swollman errx(1, _PATH_ISO3166 21219872Swollman ":%d: country code `%s' multiply defined: %s", 21319872Swollman lineno, t, cp->name); 21419872Swollman cp->name = strdup(name); 21519872Swollman cp->tlc = strdup(t); 21619872Swollman } 21719872Swollman 21819872Swollman fclose(fp); 21919872Swollman} 22019872Swollman 22119872Swollmanstatic void 22219872Swollmanadd_zone_to_country(int lineno, const char *tlc, const char *descr, 22319872Swollman const char *file, struct continent *cont) 22419872Swollman{ 22519872Swollman struct zone *zp; 22619872Swollman struct country *cp; 22719872Swollman 22819872Swollman if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 22919872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", 23019872Swollman lineno, tlc); 23119872Swollman 23219872Swollman cp = &countries[CODE2INT(tlc)]; 23319872Swollman if (cp->name == 0) 23419872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", 23519872Swollman lineno, tlc); 23619872Swollman 23719872Swollman if (descr) { 23819872Swollman if (cp->nzones < 0) 23919872Swollman errx(1, _PATH_ZONETAB 24019872Swollman ":%d: conflicting zone definition", lineno); 24119872Swollman 24219872Swollman zp = malloc(sizeof *zp); 24319872Swollman if (zp == 0) 24419872Swollman err(1, "malloc(%lu)", (unsigned long)sizeof *zp); 24519872Swollman 24619872Swollman if (cp->nzones == 0) 24719872Swollman TAILQ_INIT(&cp->zones); 24819872Swollman 24919872Swollman zp->descr = strdup(descr); 25019872Swollman zp->filename = strdup(file); 25119872Swollman zp->continent = cont; 25219872Swollman TAILQ_INSERT_TAIL(&cp->zones, zp, link); 25319872Swollman cp->nzones++; 25419872Swollman } else { 25519872Swollman if (cp->nzones > 0) 25619872Swollman errx(1, _PATH_ZONETAB 25719872Swollman ":%d: zone must have description", lineno); 25819872Swollman if (cp->nzones < 0) 25919872Swollman errx(1, _PATH_ZONETAB 26019872Swollman ":%d: zone multiply defined", lineno); 26119872Swollman cp->nzones = -1; 26219872Swollman cp->filename = strdup(file); 26319872Swollman cp->continent = cont; 26419872Swollman } 26519872Swollman} 26619872Swollman 26719872Swollman/* 26819872Swollman * This comparison function intentionally sorts all of the null-named 26919872Swollman * ``countries''---i.e., the codes that don't correspond to a real 27019872Swollman * country---to the end. Everything else is lexical by country name. 27119872Swollman */ 27219872Swollmanstatic int 27319872Swollmancompare_countries(const void *xa, const void *xb) 27419872Swollman{ 27519872Swollman const struct country *a = xa, *b = xb; 27619872Swollman 27719872Swollman if (a->name == 0 && b->name == 0) 27819872Swollman return 0; 27919872Swollman if (a->name == 0 && b->name != 0) 28019872Swollman return 1; 28119872Swollman if (b->name == 0) 28219872Swollman return -1; 28319872Swollman 28419872Swollman return strcmp(a->name, b->name); 28519872Swollman} 28619872Swollman 28719872Swollman/* 28819872Swollman * This must be done AFTER all zone descriptions are read, since it breaks 28919872Swollman * CODE2INT(). 29019872Swollman */ 29119872Swollmanstatic void 29219872Swollmansort_countries(void) 29319872Swollman{ 29419872Swollman qsort(countries, 576, sizeof countries[0], compare_countries); 29519872Swollman} 29619872Swollman 29719872Swollmanstatic void 29819872Swollmanread_zones(void) 29919872Swollman{ 30019872Swollman FILE *fp; 30119872Swollman char *line; 30219872Swollman size_t len; 30319872Swollman int lineno; 30419872Swollman char *tlc, *coord, *file, *descr, *p; 30519872Swollman char contbuf[16]; 30619872Swollman struct continent *cont; 30719872Swollman 30819872Swollman fp = fopen(_PATH_ZONETAB, "r"); 30919872Swollman if (!fp) 31019872Swollman err(1, _PATH_ZONETAB); 31119872Swollman lineno = 0; 31219872Swollman 31319872Swollman while ((line = fgetln(fp, &len)) != 0) { 31419872Swollman lineno++; 31519872Swollman if (line[len - 1] != '\n') 31619872Swollman errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); 31719872Swollman line[len - 1] = '\0'; 31819872Swollman if (line[0] == '#') 31919872Swollman continue; 32019872Swollman 32119872Swollman tlc = strsep(&line, "\t"); 32219872Swollman if (strlen(tlc) != 2) 32319872Swollman errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", 32419872Swollman lineno, tlc); 32519872Swollman coord = strsep(&line, "\t"); 32619872Swollman file = strsep(&line, "\t"); 32719872Swollman p = strchr(file, '/'); 32819872Swollman if (p == 0) 32919872Swollman errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", 33019872Swollman lineno, file); 33119872Swollman contbuf[0] = '\0'; 33219872Swollman strncat(contbuf, file, p - file); 33319872Swollman cont = find_continent(contbuf); 33419872Swollman if (!cont) 33519872Swollman errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", 33619872Swollman lineno, contbuf); 33719872Swollman 33819872Swollman descr = (line && *line) ? line : 0; 33919872Swollman 34019872Swollman add_zone_to_country(lineno, tlc, descr, file, cont); 34119872Swollman } 34219872Swollman fclose(fp); 34319872Swollman} 34419872Swollman 34519872Swollmanstatic void 34619872Swollmanmake_menus(void) 34719872Swollman{ 34819872Swollman struct country *cp; 34919872Swollman struct zone *zp, *zp2; 35019872Swollman struct continent *cont; 35119872Swollman dialogMenuItem *dmi; 35219872Swollman int i; 35319872Swollman 35419872Swollman /* 35519872Swollman * First, count up all the countries in each continent/ocean. 35619872Swollman * Be careful to count those countries which have multiple zones 35719872Swollman * only once for each. NB: some countries are in multiple 35819872Swollman * continents/oceans. 35919872Swollman */ 36019872Swollman for (cp = countries; cp->name; cp++) { 36119872Swollman if (cp->nzones == 0) 36219872Swollman continue; 36319872Swollman if (cp->nzones < 0) { 36419872Swollman cp->continent->nitems++; 36519872Swollman } else { 36619872Swollman for (zp = cp->zones.tqh_first; zp; 36719872Swollman zp = zp->link.tqe_next) { 36819872Swollman cont = zp->continent; 36919872Swollman for (zp2 = cp->zones.tqh_first; 37019872Swollman zp2->continent != cont; 37119872Swollman zp2 = zp2->link.tqe_next) 37219872Swollman ; 37319872Swollman if (zp2 == zp) 37419872Swollman zp->continent->nitems++; 37519872Swollman } 37619872Swollman } 37719872Swollman } 37819872Swollman 37919872Swollman /* 38019872Swollman * Now allocate memory for the country menus. We set 38119872Swollman * nitems back to zero so that we can use it for counting 38219872Swollman * again when we actually build the menus. 38319872Swollman */ 38419872Swollman for (i = 0; i < NCONTINENTS; i++) { 38519872Swollman continent_names[i].continent->menu = 38619872Swollman malloc(sizeof(dialogMenuItem) * 38719872Swollman continent_names[i].continent->nitems); 38819872Swollman if (continent_names[i].continent->menu == 0) 38919872Swollman err(1, "malloc for continent menu"); 39019872Swollman continent_names[i].continent->nitems = 0; 39119872Swollman } 39219872Swollman 39319872Swollman /* 39419872Swollman * Now that memory is allocated, create the menu items for 39519872Swollman * each continent. For multiple-zone countries, also create 39619872Swollman * the country's zone submenu. 39719872Swollman */ 39819872Swollman for (cp = countries; cp->name; cp++) { 39919872Swollman if (cp->nzones == 0) 40019872Swollman continue; 40119872Swollman if (cp->nzones < 0) { 40219872Swollman dmi = &cp->continent->menu[cp->continent->nitems]; 40319872Swollman memset(dmi, 0, sizeof *dmi); 40419872Swollman asprintf(&dmi->prompt, "%d", 40519872Swollman ++cp->continent->nitems); 40619872Swollman dmi->title = cp->name; 40719872Swollman dmi->checked = 0; 40819872Swollman dmi->fire = set_zone_whole_country; 40919872Swollman dmi->selected = 0; 41019872Swollman dmi->data = cp; 41119872Swollman } else { 41219872Swollman cp->submenu = malloc(cp->nzones * sizeof *dmi); 41319872Swollman if (cp->submenu == 0) 41419872Swollman err(1, "malloc for submenu"); 41519872Swollman cp->nzones = 0; 41619872Swollman for (zp = cp->zones.tqh_first; zp; 41719872Swollman zp = zp->link.tqe_next) { 41819872Swollman cont = zp->continent; 41919872Swollman dmi = &cp->submenu[cp->nzones]; 42019872Swollman memset(dmi, 0, sizeof *dmi); 42119872Swollman asprintf(&dmi->prompt, "%d", 42219872Swollman ++cp->nzones); 42319872Swollman dmi->title = zp->descr; 42419872Swollman dmi->checked = 0; 42519872Swollman dmi->fire = set_zone_multi; 42619872Swollman dmi->selected = 0; 42719872Swollman dmi->data = zp; 42819872Swollman 42919872Swollman for (zp2 = cp->zones.tqh_first; 43019872Swollman zp2->continent != cont; 43119872Swollman zp2 = zp2->link.tqe_next) 43219872Swollman ; 43319872Swollman if (zp2 != zp) 43419872Swollman continue; 43519872Swollman 43619872Swollman dmi = &cont->menu[cont->nitems]; 43719872Swollman memset(dmi, 0, sizeof *dmi); 43819872Swollman asprintf(&dmi->prompt, "%d", ++cont->nitems); 43919872Swollman dmi->title = cp->name; 44019872Swollman dmi->checked = 0; 44119872Swollman dmi->fire = set_zone_menu; 44219872Swollman dmi->selected = 0; 44319872Swollman dmi->data = cp; 44419872Swollman } 44519872Swollman } 44619872Swollman } 44719872Swollman} 44819872Swollman 44919872Swollmanstatic int 45019872Swollmanset_zone_menu(dialogMenuItem *dmi) 45119872Swollman{ 45219872Swollman int rv; 45319872Swollman char buf[256]; 45419872Swollman struct country *cp = dmi->data; 45519872Swollman int menulen; 45619872Swollman 45719872Swollman snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 45819872Swollman menulen = cp->nzones < 16 ? cp->nzones : 16; 45919872Swollman rv = dialog_menu(buf, "Select a zone which observes the same time as " 46019872Swollman "your locality.", -1, -1, menulen, -cp->nzones, 46119872Swollman cp->submenu, 0, 0, 0); 46219872Swollman if (rv != 0) 46319872Swollman return DITEM_RECREATE; 46419872Swollman return DITEM_LEAVE_MENU; 46519872Swollman} 46619872Swollman 46719872Swollmanstatic int 46819872Swollmaninstall_zone_file(const char *filename) 46919872Swollman{ 47019872Swollman struct stat sb; 47119872Swollman int fd1, fd2; 47219872Swollman int copymode; 47319872Swollman char *msg; 47419872Swollman ssize_t len; 47519872Swollman char buf[1024]; 47619872Swollman 47719872Swollman if (lstat(_PATH_LOCALTIME, &sb) < 0) 47819872Swollman /* Nothing there yet... */ 47919872Swollman copymode = 1; 48019872Swollman else if(S_ISLNK(sb.st_mode)) 48119872Swollman copymode = 0; 48219872Swollman else 48319872Swollman copymode = 1; 48419872Swollman 48519872Swollman if (copymode) 48619872Swollman asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 48719872Swollman else 48819872Swollman asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 48919872Swollman " to %s", filename); 49019872Swollman 49119872Swollman dialog_notify(msg); 49219872Swollman free(msg); 49319872Swollman 49419872Swollman if (reallydoit) { 49519872Swollman if (copymode) { 49619872Swollman fd1 = open(filename, O_RDONLY, 0); 49719872Swollman if (fd1 < 0) { 49819872Swollman asprintf(&msg, "Could not open %s: %s", 49919872Swollman filename, strerror(errno)); 50019872Swollman dialog_mesgbox("Error", msg, 8, 72); 50119872Swollman free(msg); 50219872Swollman return DITEM_FAILURE | DITEM_RECREATE; 50319872Swollman } 50419872Swollman 50519872Swollman unlink(_PATH_LOCALTIME); 50619872Swollman fd2 = open(_PATH_LOCALTIME, 50719872Swollman O_CREAT | O_EXCL | O_WRONLY, 50819872Swollman 0444); 50919872Swollman if (fd2 < 0) { 51019872Swollman asprintf(&msg, "Could not open " 51119872Swollman _PATH_LOCALTIME ": %s", 51219872Swollman strerror(errno)); 51319872Swollman dialog_mesgbox("Error", msg, 8, 72); 51419872Swollman free(msg); 51519872Swollman return DITEM_FAILURE | DITEM_RECREATE; 51619872Swollman } 51719872Swollman 51819872Swollman while ((len = read(fd1, buf, sizeof buf)) > 0) 51919872Swollman len = write(fd2, buf, len); 52019872Swollman 52119872Swollman if (len == -1) { 52219872Swollman asprintf(&msg, "Error copying %s to " 52319872Swollman _PATH_LOCALTIME ": %s", 52419872Swollman strerror(errno)); 52519872Swollman dialog_mesgbox("Error", msg, 8, 72); 52619872Swollman free(msg); 52719872Swollman /* Better to leave none than a corrupt one. */ 52819872Swollman unlink(_PATH_LOCALTIME); 52919872Swollman return DITEM_FAILURE | DITEM_RECREATE; 53019872Swollman } 53119872Swollman close(fd1); 53219872Swollman close(fd2); 53319872Swollman } else { 53419872Swollman if (access(filename, R_OK) != 0) { 53519872Swollman asprintf(&msg, "Cannot access %s: %s", 53619872Swollman filename, strerror(errno)); 53719872Swollman dialog_mesgbox("Error", msg, 8, 72); 53819872Swollman free(msg); 53919872Swollman return DITEM_FAILURE | DITEM_RECREATE; 54019872Swollman } 54119872Swollman unlink(_PATH_LOCALTIME); 54219872Swollman if (symlink(filename, _PATH_LOCALTIME) < 0) { 54319872Swollman asprintf(&msg, "Cannot create symbolic link " 54419872Swollman _PATH_LOCALTIME " to %s: %s", 54519872Swollman filename, strerror(errno)); 54619872Swollman dialog_mesgbox("Error", msg, 8, 72); 54719872Swollman free(msg); 54819872Swollman return DITEM_FAILURE | DITEM_RECREATE; 54919872Swollman } 55019872Swollman } 55119872Swollman } 55219872Swollman 55319872Swollman if (copymode) 55419872Swollman asprintf(&msg, "Copied timezone file from %s to " 55519872Swollman _PATH_LOCALTIME, filename); 55619872Swollman else 55719872Swollman asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 55819872Swollman " to %s", filename); 55919872Swollman 56019872Swollman dialog_mesgbox("Done", msg, 8, 72); 56119872Swollman free(msg); 56219872Swollman return DITEM_LEAVE_MENU; 56319872Swollman} 56419872Swollman 56519872Swollmanstatic int 56619872Swollmanconfirm_zone(const char *filename) 56719872Swollman{ 56819872Swollman char *msg; 56919872Swollman struct tm *tm; 57019872Swollman time_t t = time(0); 57119872Swollman int rv; 57219872Swollman 57319872Swollman setenv("TZ", filename, 1); 57419872Swollman tzset(); 57519872Swollman tm = localtime(&t); 57619872Swollman 57719872Swollman asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 57819872Swollman tm->tm_zone); 57919872Swollman rv = !dialog_yesno("Confirmation", msg, 4, 72); 58019872Swollman free(msg); 58119872Swollman return rv; 58219872Swollman} 58319872Swollman 58419872Swollmanstatic int 58519872Swollmanset_zone_multi(dialogMenuItem *dmi) 58619872Swollman{ 58719872Swollman char *fn; 58819872Swollman struct zone *zp = dmi->data; 58919872Swollman int rv; 59019872Swollman 59119872Swollman if (!confirm_zone(zp->filename)) 59219872Swollman return DITEM_FAILURE | DITEM_RECREATE; 59319872Swollman 59419872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 59519872Swollman rv = install_zone_file(fn); 59619872Swollman free(fn); 59719872Swollman return rv; 59819872Swollman} 59919872Swollman 60019872Swollmanstatic int 60119872Swollmanset_zone_whole_country(dialogMenuItem *dmi) 60219872Swollman{ 60319872Swollman char *fn; 60419872Swollman struct country *cp = dmi->data; 60519872Swollman int rv; 60619872Swollman 60719872Swollman if (!confirm_zone(cp->filename)) 60819872Swollman return DITEM_FAILURE | DITEM_RECREATE; 60919872Swollman 61019872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 61119872Swollman rv = install_zone_file(fn); 61219872Swollman free(fn); 61319872Swollman return rv; 61419872Swollman} 61519872Swollman 61619872Swollmanint 61719872Swollmanmain(int argc, char **argv) 61819872Swollman{ 61919872Swollman int c; 62019872Swollman 62119872Swollman while ((c = getopt(argc, argv, "n")) != -1) { 62219872Swollman switch(c) { 62319872Swollman case 'n': 62419872Swollman reallydoit = 0; 62519872Swollman break; 62619872Swollman 62719872Swollman default: 62819872Swollman fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], 62919872Swollman argv[0]); 63019872Swollman exit(1); 63119872Swollman } 63219872Swollman } 63319872Swollman 63419872Swollman if (optind != argc) { 63519872Swollman fprintf(stderr, "%s: usage:\n\t%s [-n]\n", argv[0], argv[0]); 63619872Swollman exit(1); 63719872Swollman } 63819872Swollman 63919872Swollman read_iso3166_table(); 64019872Swollman read_zones(); 64119872Swollman sort_countries(); 64219872Swollman make_menus(); 64319872Swollman 64419872Swollman init_dialog(); 64519872Swollman dialog_menu("Time Zone Selector", "Select a region", -1, -1, 64619887Sjoerg NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 64719872Swollman end_dialog(); 64819872Swollman return 0; 64919872Swollman} 65019872Swollman 651