tzsetup.c revision 70092
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 */ 2919872Swollman 3019872Swollman/* 3119872Swollman * Second attempt at a `tzmenu' program, using the separate description 3219872Swollman * files provided in newer tzdata releases. 3319872Swollman */ 3419872Swollman 3530763Scharnier#ifndef lint 3630763Scharnierstatic const char rcsid[] = 3750479Speter "$FreeBSD: head/usr.sbin/tzsetup/tzsetup.c 70092 2000-12-16 05:29:38Z jkh $"; 3830763Scharnier#endif /* not lint */ 3930763Scharnier 4019872Swollman#include <sys/types.h> 4119872Swollman#include <dialog.h> 4219872Swollman#include <err.h> 4319872Swollman#include <errno.h> 4419872Swollman#include <stdio.h> 4519872Swollman#include <stdlib.h> 4619872Swollman#include <string.h> 4766907Swollman#include <time.h> 4819872Swollman#include <unistd.h> 4919872Swollman 5019872Swollman#include <sys/fcntl.h> 5119872Swollman#include <sys/queue.h> 5219872Swollman#include <sys/stat.h> 5319872Swollman 5419872Swollman#include "paths.h" 5519872Swollman 5619872Swollmanstatic int reallydoit = 1; 5719872Swollman 5819872Swollmanstatic int continent_country_menu(dialogMenuItem *); 5919872Swollmanstatic int set_zone_multi(dialogMenuItem *); 6019872Swollmanstatic int set_zone_whole_country(dialogMenuItem *); 6119872Swollmanstatic int set_zone_menu(dialogMenuItem *); 6219872Swollman 6319872Swollmanstruct continent { 6419872Swollman dialogMenuItem *menu; 6519872Swollman int nitems; 6619872Swollman int ch; 6719872Swollman int sc; 6819872Swollman}; 6919872Swollman 7019872Swollmanstatic struct continent africa, america, antarctica, arctic, asia, atlantic; 7119872Swollmanstatic struct continent australia, europe, indian, pacific; 7219872Swollman 7319872Swollmanstatic struct continent_names { 7419872Swollman char *name; 7519872Swollman struct continent *continent; 7619872Swollman} continent_names[] = { 7719872Swollman { "Africa", &africa }, { "America", &america }, 7819872Swollman { "Antarctica", &antarctica }, { "Arctic", &arctic }, 7919872Swollman { "Asia", &asia }, 8019872Swollman { "Atlantic", &atlantic }, { "Australia", &australia }, 8119872Swollman { "Europe", &europe }, { "Indian", &indian }, { "Pacific", &pacific } 8219872Swollman}; 8319872Swollman 8419872Swollmanstatic dialogMenuItem continents[] = { 8519872Swollman { "1", "Africa", 0, continent_country_menu, 0, &africa }, 8619872Swollman { "2", "America -- North and South", 0, continent_country_menu, 0, 8719872Swollman &america }, 8819872Swollman { "3", "Antarctica", 0, continent_country_menu, 0, &antarctica }, 8919872Swollman { "4", "Arctic Ocean", 0, continent_country_menu, 0, &arctic }, 9019872Swollman { "5", "Asia", 0, continent_country_menu, 0, &asia }, 9119872Swollman { "6", "Atlantic Ocean", 0, continent_country_menu, 0, &atlantic }, 9219872Swollman { "7", "Australia", 0, continent_country_menu, 0, &australia }, 9319872Swollman { "8", "Europe", 0, continent_country_menu, 0, &europe }, 9419872Swollman { "9", "Indian Ocean", 0, continent_country_menu, 0, &indian }, 9519872Swollman { "0", "Pacific Ocean", 0, continent_country_menu, 0, &pacific } 9619872Swollman}; 9719872Swollman#define NCONTINENTS ((sizeof continents)/(sizeof continents[0])) 9819872Swollman#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) 9919872Swollman 10019872Swollmanstatic int 10119872Swollmancontinent_country_menu(dialogMenuItem *continent) 10219872Swollman{ 10319872Swollman int rv; 10419872Swollman struct continent *contp = continent->data; 10519872Swollman char title[256]; 10619872Swollman int isocean = OCEANP(continent - continents); 10719872Swollman int menulen; 10819872Swollman 10919872Swollman /* Short cut -- if there's only one country, don't post a menu. */ 11019872Swollman if (contp->nitems == 1) { 11119872Swollman return set_zone_menu(&contp->menu[0]); 11219872Swollman } 11319872Swollman 11419872Swollman /* It's amazing how much good grammar really matters... */ 11519872Swollman if (!isocean) 11619872Swollman snprintf(title, sizeof title, "Countries in %s", 11719872Swollman continent->title); 11819872Swollman else 11919872Swollman snprintf(title, sizeof title, "Islands and groups in the %s", 12019872Swollman continent->title); 12119872Swollman 12219872Swollman menulen = contp->nitems < 16 ? contp->nitems : 16; 12319872Swollman rv = dialog_menu(title, (isocean ? "Select an island or group" 12419872Swollman : "Select a country"), -1, -1, menulen, 12519872Swollman -contp->nitems, contp->menu, 0, &contp->ch, 12619872Swollman &contp->sc); 12719872Swollman if (rv == 0) 12819872Swollman return DITEM_LEAVE_MENU; 12919872Swollman return DITEM_RECREATE; 13019872Swollman} 13119872Swollman 13219872Swollmanstatic struct continent * 13319872Swollmanfind_continent(const char *name) 13419872Swollman{ 13519872Swollman int i; 13619872Swollman 13719872Swollman for (i = 0; i < NCONTINENTS; i++) { 13819872Swollman if (strcmp(name, continent_names[i].name) == 0) 13919872Swollman return continent_names[i].continent; 14019872Swollman } 14119872Swollman return 0; 14219872Swollman} 14319872Swollman 14419872Swollmanstruct country { 14519872Swollman char *name; 14619872Swollman char *tlc; 14719872Swollman int nzones; 14819872Swollman char *filename; /* use iff nzones < 0 */ 14919872Swollman struct continent *continent; /* use iff nzones < 0 */ 15060938Sjake TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ 15119872Swollman dialogMenuItem *submenu; /* use iff nzones > 0 */ 15219872Swollman}; 15319872Swollman 15419872Swollmanstruct zone { 15560938Sjake TAILQ_ENTRY(zone) link; 15619872Swollman char *descr; 15719872Swollman char *filename; 15819872Swollman struct continent *continent; 15919872Swollman}; 16019872Swollman 16119872Swollman/* 16219872Swollman * This is the easiest organization... we use ISO 3166 country codes, 16319872Swollman * of the two-letter variety, so we just size this array to suit. 16419872Swollman * Beats worrying about dynamic allocation. 16519872Swollman */ 16622181Sjhay#define NCOUNTRIES (26*26) 16722181Sjhaystatic struct country countries[NCOUNTRIES]; 16819872Swollman#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 16919872Swollman 17019872Swollman/* 17119872Swollman * Read the ISO 3166 country code database in _PATH_ISO3166 17219872Swollman * (/usr/share/misc/iso3166). On error, exit via err(3). 17319872Swollman */ 17419872Swollmanstatic void 17519872Swollmanread_iso3166_table(void) 17619872Swollman{ 17719872Swollman FILE *fp; 17819872Swollman char *s, *t, *name; 17919872Swollman size_t len; 18019872Swollman int lineno; 18119872Swollman struct country *cp; 18219872Swollman 18319872Swollman fp = fopen(_PATH_ISO3166, "r"); 18419872Swollman if (!fp) 18519872Swollman err(1, _PATH_ISO3166); 18619872Swollman lineno = 0; 18719872Swollman 18819872Swollman while ((s = fgetln(fp, &len)) != 0) { 18919872Swollman lineno++; 19019872Swollman if (s[len - 1] != '\n') 19119872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 19219872Swollman s[len - 1] = '\0'; 19330999Sjoerg if (s[0] == '#' || strspn(s, " \t") == len - 1) 19419872Swollman continue; 19519872Swollman 19619872Swollman /* Isolate the two-letter code. */ 19719872Swollman t = strsep(&s, "\t"); 19819872Swollman if (t == 0 || strlen(t) != 2) 19919872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20019872Swollman if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 20119872Swollman errx(1, _PATH_ISO3166 ":%d: invalid code `%s'", 20219872Swollman lineno, t); 20319872Swollman 20419872Swollman /* Now skip past the three-letter and numeric codes. */ 20519872Swollman name = strsep(&s, "\t"); /* 3-let */ 20619872Swollman if (name == 0 || strlen(name) != 3) 20719872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 20819872Swollman name = strsep(&s, "\t"); /* numeric */ 20919872Swollman if (name == 0 || strlen(name) != 3) 21019872Swollman errx(1, _PATH_ISO3166 ":%d: invalid format", lineno); 21119872Swollman 21219872Swollman name = s; 21319872Swollman 21419872Swollman cp = &countries[CODE2INT(t)]; 21519872Swollman if (cp->name) 21619872Swollman errx(1, _PATH_ISO3166 21719872Swollman ":%d: country code `%s' multiply defined: %s", 21819872Swollman lineno, t, cp->name); 21919872Swollman cp->name = strdup(name); 22056487Scharnier if (cp->name == NULL) 22156487Scharnier errx(1, "malloc failed"); 22219872Swollman cp->tlc = strdup(t); 22356487Scharnier if (cp->tlc == NULL) 22456487Scharnier errx(1, "malloc failed"); 22519872Swollman } 22619872Swollman 22719872Swollman fclose(fp); 22819872Swollman} 22919872Swollman 23019872Swollmanstatic void 23119872Swollmanadd_zone_to_country(int lineno, const char *tlc, const char *descr, 23219872Swollman const char *file, struct continent *cont) 23319872Swollman{ 23419872Swollman struct zone *zp; 23519872Swollman struct country *cp; 23619872Swollman 23719872Swollman if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 23819872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' invalid", 23919872Swollman lineno, tlc); 24019872Swollman 24119872Swollman cp = &countries[CODE2INT(tlc)]; 24219872Swollman if (cp->name == 0) 24319872Swollman errx(1, _PATH_ZONETAB ":%d: country code `%s' unknown", 24419872Swollman lineno, tlc); 24519872Swollman 24619872Swollman if (descr) { 24719872Swollman if (cp->nzones < 0) 24819872Swollman errx(1, _PATH_ZONETAB 24919872Swollman ":%d: conflicting zone definition", lineno); 25019872Swollman 25119872Swollman zp = malloc(sizeof *zp); 25219872Swollman if (zp == 0) 25356487Scharnier errx(1, "malloc(%lu)", (unsigned long)sizeof *zp); 25419872Swollman 25519872Swollman if (cp->nzones == 0) 25619872Swollman TAILQ_INIT(&cp->zones); 25719872Swollman 25819872Swollman zp->descr = strdup(descr); 25956487Scharnier if (zp->descr == NULL) 26056487Scharnier errx(1, "malloc failed"); 26119872Swollman zp->filename = strdup(file); 26256487Scharnier if (zp->filename == NULL) 26356487Scharnier errx(1, "malloc failed"); 26419872Swollman zp->continent = cont; 26519872Swollman TAILQ_INSERT_TAIL(&cp->zones, zp, link); 26619872Swollman cp->nzones++; 26719872Swollman } else { 26819872Swollman if (cp->nzones > 0) 26919872Swollman errx(1, _PATH_ZONETAB 27019872Swollman ":%d: zone must have description", lineno); 27119872Swollman if (cp->nzones < 0) 27219872Swollman errx(1, _PATH_ZONETAB 27319872Swollman ":%d: zone multiply defined", lineno); 27419872Swollman cp->nzones = -1; 27519872Swollman cp->filename = strdup(file); 27656487Scharnier if (cp->filename == NULL) 27756487Scharnier errx(1, "malloc failed"); 27819872Swollman cp->continent = cont; 27919872Swollman } 28019872Swollman} 28119872Swollman 28219872Swollman/* 28319872Swollman * This comparison function intentionally sorts all of the null-named 28419872Swollman * ``countries''---i.e., the codes that don't correspond to a real 28519872Swollman * country---to the end. Everything else is lexical by country name. 28619872Swollman */ 28719872Swollmanstatic int 28819872Swollmancompare_countries(const void *xa, const void *xb) 28919872Swollman{ 29019872Swollman const struct country *a = xa, *b = xb; 29119872Swollman 29219872Swollman if (a->name == 0 && b->name == 0) 29319872Swollman return 0; 29419872Swollman if (a->name == 0 && b->name != 0) 29519872Swollman return 1; 29619872Swollman if (b->name == 0) 29719872Swollman return -1; 29819872Swollman 29919872Swollman return strcmp(a->name, b->name); 30019872Swollman} 30119872Swollman 30219872Swollman/* 30319872Swollman * This must be done AFTER all zone descriptions are read, since it breaks 30419872Swollman * CODE2INT(). 30519872Swollman */ 30619872Swollmanstatic void 30719872Swollmansort_countries(void) 30819872Swollman{ 30922181Sjhay qsort(countries, NCOUNTRIES, sizeof countries[0], compare_countries); 31019872Swollman} 31119872Swollman 31219872Swollmanstatic void 31319872Swollmanread_zones(void) 31419872Swollman{ 31519872Swollman FILE *fp; 31619872Swollman char *line; 31719872Swollman size_t len; 31819872Swollman int lineno; 31919872Swollman char *tlc, *coord, *file, *descr, *p; 32019872Swollman char contbuf[16]; 32119872Swollman struct continent *cont; 32219872Swollman 32319872Swollman fp = fopen(_PATH_ZONETAB, "r"); 32419872Swollman if (!fp) 32519872Swollman err(1, _PATH_ZONETAB); 32619872Swollman lineno = 0; 32719872Swollman 32819872Swollman while ((line = fgetln(fp, &len)) != 0) { 32919872Swollman lineno++; 33019872Swollman if (line[len - 1] != '\n') 33119872Swollman errx(1, _PATH_ZONETAB ":%d: invalid format", lineno); 33219872Swollman line[len - 1] = '\0'; 33319872Swollman if (line[0] == '#') 33419872Swollman continue; 33519872Swollman 33619872Swollman tlc = strsep(&line, "\t"); 33719872Swollman if (strlen(tlc) != 2) 33819872Swollman errx(1, _PATH_ZONETAB ":%d: invalid country code `%s'", 33919872Swollman lineno, tlc); 34019872Swollman coord = strsep(&line, "\t"); 34119872Swollman file = strsep(&line, "\t"); 34219872Swollman p = strchr(file, '/'); 34319872Swollman if (p == 0) 34419872Swollman errx(1, _PATH_ZONETAB ":%d: invalid zone name `%s'", 34519872Swollman lineno, file); 34619872Swollman contbuf[0] = '\0'; 34719872Swollman strncat(contbuf, file, p - file); 34819872Swollman cont = find_continent(contbuf); 34919872Swollman if (!cont) 35019872Swollman errx(1, _PATH_ZONETAB ":%d: invalid region `%s'", 35119872Swollman lineno, contbuf); 35219872Swollman 35319872Swollman descr = (line && *line) ? line : 0; 35419872Swollman 35519872Swollman add_zone_to_country(lineno, tlc, descr, file, cont); 35619872Swollman } 35719872Swollman fclose(fp); 35819872Swollman} 35919872Swollman 36019872Swollmanstatic void 36119872Swollmanmake_menus(void) 36219872Swollman{ 36319872Swollman struct country *cp; 36419872Swollman struct zone *zp, *zp2; 36519872Swollman struct continent *cont; 36619872Swollman dialogMenuItem *dmi; 36719872Swollman int i; 36819872Swollman 36919872Swollman /* 37019872Swollman * First, count up all the countries in each continent/ocean. 37119872Swollman * Be careful to count those countries which have multiple zones 37219872Swollman * only once for each. NB: some countries are in multiple 37319872Swollman * continents/oceans. 37419872Swollman */ 37519872Swollman for (cp = countries; cp->name; cp++) { 37619872Swollman if (cp->nzones == 0) 37719872Swollman continue; 37819872Swollman if (cp->nzones < 0) { 37919872Swollman cp->continent->nitems++; 38019872Swollman } else { 38119872Swollman for (zp = cp->zones.tqh_first; zp; 38219872Swollman zp = zp->link.tqe_next) { 38319872Swollman cont = zp->continent; 38419872Swollman for (zp2 = cp->zones.tqh_first; 38519872Swollman zp2->continent != cont; 38619872Swollman zp2 = zp2->link.tqe_next) 38719872Swollman ; 38819872Swollman if (zp2 == zp) 38919872Swollman zp->continent->nitems++; 39019872Swollman } 39119872Swollman } 39219872Swollman } 39319872Swollman 39419872Swollman /* 39519872Swollman * Now allocate memory for the country menus. We set 39619872Swollman * nitems back to zero so that we can use it for counting 39719872Swollman * again when we actually build the menus. 39819872Swollman */ 39919872Swollman for (i = 0; i < NCONTINENTS; i++) { 40019872Swollman continent_names[i].continent->menu = 40119872Swollman malloc(sizeof(dialogMenuItem) * 40219872Swollman continent_names[i].continent->nitems); 40319872Swollman if (continent_names[i].continent->menu == 0) 40456487Scharnier errx(1, "malloc for continent menu"); 40519872Swollman continent_names[i].continent->nitems = 0; 40619872Swollman } 40719872Swollman 40819872Swollman /* 40919872Swollman * Now that memory is allocated, create the menu items for 41019872Swollman * each continent. For multiple-zone countries, also create 41119872Swollman * the country's zone submenu. 41219872Swollman */ 41319872Swollman for (cp = countries; cp->name; cp++) { 41419872Swollman if (cp->nzones == 0) 41519872Swollman continue; 41619872Swollman if (cp->nzones < 0) { 41719872Swollman dmi = &cp->continent->menu[cp->continent->nitems]; 41819872Swollman memset(dmi, 0, sizeof *dmi); 41919872Swollman asprintf(&dmi->prompt, "%d", 42019872Swollman ++cp->continent->nitems); 42119872Swollman dmi->title = cp->name; 42219872Swollman dmi->checked = 0; 42319872Swollman dmi->fire = set_zone_whole_country; 42419872Swollman dmi->selected = 0; 42519872Swollman dmi->data = cp; 42619872Swollman } else { 42719872Swollman cp->submenu = malloc(cp->nzones * sizeof *dmi); 42819872Swollman if (cp->submenu == 0) 42956487Scharnier errx(1, "malloc for submenu"); 43019872Swollman cp->nzones = 0; 43119872Swollman for (zp = cp->zones.tqh_first; zp; 43219872Swollman zp = zp->link.tqe_next) { 43319872Swollman cont = zp->continent; 43419872Swollman dmi = &cp->submenu[cp->nzones]; 43519872Swollman memset(dmi, 0, sizeof *dmi); 43619872Swollman asprintf(&dmi->prompt, "%d", 43719872Swollman ++cp->nzones); 43819872Swollman dmi->title = zp->descr; 43919872Swollman dmi->checked = 0; 44019872Swollman dmi->fire = set_zone_multi; 44119872Swollman dmi->selected = 0; 44219872Swollman dmi->data = zp; 44319872Swollman 44419872Swollman for (zp2 = cp->zones.tqh_first; 44519872Swollman zp2->continent != cont; 44619872Swollman zp2 = zp2->link.tqe_next) 44719872Swollman ; 44819872Swollman if (zp2 != zp) 44919872Swollman continue; 45019872Swollman 45119872Swollman dmi = &cont->menu[cont->nitems]; 45219872Swollman memset(dmi, 0, sizeof *dmi); 45319872Swollman asprintf(&dmi->prompt, "%d", ++cont->nitems); 45419872Swollman dmi->title = cp->name; 45519872Swollman dmi->checked = 0; 45619872Swollman dmi->fire = set_zone_menu; 45719872Swollman dmi->selected = 0; 45819872Swollman dmi->data = cp; 45919872Swollman } 46019872Swollman } 46119872Swollman } 46219872Swollman} 46319872Swollman 46419872Swollmanstatic int 46519872Swollmanset_zone_menu(dialogMenuItem *dmi) 46619872Swollman{ 46719872Swollman int rv; 46819872Swollman char buf[256]; 46919872Swollman struct country *cp = dmi->data; 47019872Swollman int menulen; 47119872Swollman 47219872Swollman snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 47319872Swollman menulen = cp->nzones < 16 ? cp->nzones : 16; 47419872Swollman rv = dialog_menu(buf, "Select a zone which observes the same time as " 47519872Swollman "your locality.", -1, -1, menulen, -cp->nzones, 47619872Swollman cp->submenu, 0, 0, 0); 47719872Swollman if (rv != 0) 47819872Swollman return DITEM_RECREATE; 47919872Swollman return DITEM_LEAVE_MENU; 48019872Swollman} 48119872Swollman 48219872Swollmanstatic int 48319872Swollmaninstall_zone_file(const char *filename) 48419872Swollman{ 48519872Swollman struct stat sb; 48619872Swollman int fd1, fd2; 48719872Swollman int copymode; 48819872Swollman char *msg; 48919872Swollman ssize_t len; 49019872Swollman char buf[1024]; 49119872Swollman 49219872Swollman if (lstat(_PATH_LOCALTIME, &sb) < 0) 49319872Swollman /* Nothing there yet... */ 49419872Swollman copymode = 1; 49519872Swollman else if(S_ISLNK(sb.st_mode)) 49619872Swollman copymode = 0; 49719872Swollman else 49819872Swollman copymode = 1; 49919872Swollman 50021915Sjkh#ifdef VERBOSE 50119872Swollman if (copymode) 50219872Swollman asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 50319872Swollman else 50419872Swollman asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 50519872Swollman " to %s", filename); 50619872Swollman 50719872Swollman dialog_notify(msg); 50819872Swollman free(msg); 50921915Sjkh#endif 51019872Swollman 51119872Swollman if (reallydoit) { 51219872Swollman if (copymode) { 51319872Swollman fd1 = open(filename, O_RDONLY, 0); 51419872Swollman if (fd1 < 0) { 51519872Swollman asprintf(&msg, "Could not open %s: %s", 51619872Swollman filename, strerror(errno)); 51719872Swollman dialog_mesgbox("Error", msg, 8, 72); 51819872Swollman free(msg); 51919872Swollman return DITEM_FAILURE | DITEM_RECREATE; 52019872Swollman } 52119872Swollman 52219872Swollman unlink(_PATH_LOCALTIME); 52319872Swollman fd2 = open(_PATH_LOCALTIME, 52449435Sru O_CREAT|O_EXCL|O_WRONLY, 52549435Sru S_IRUSR|S_IRGRP|S_IROTH); 52619872Swollman if (fd2 < 0) { 52719872Swollman asprintf(&msg, "Could not open " 52819872Swollman _PATH_LOCALTIME ": %s", 52919872Swollman strerror(errno)); 53019872Swollman dialog_mesgbox("Error", msg, 8, 72); 53119872Swollman free(msg); 53219872Swollman return DITEM_FAILURE | DITEM_RECREATE; 53319872Swollman } 53419872Swollman 53519872Swollman while ((len = read(fd1, buf, sizeof buf)) > 0) 53619872Swollman len = write(fd2, buf, len); 53719872Swollman 53819872Swollman if (len == -1) { 53919872Swollman asprintf(&msg, "Error copying %s to " 54019872Swollman _PATH_LOCALTIME ": %s", 54149435Sru filename, strerror(errno)); 54219872Swollman dialog_mesgbox("Error", msg, 8, 72); 54319872Swollman free(msg); 54419872Swollman /* Better to leave none than a corrupt one. */ 54519872Swollman unlink(_PATH_LOCALTIME); 54619872Swollman return DITEM_FAILURE | DITEM_RECREATE; 54719872Swollman } 54819872Swollman close(fd1); 54919872Swollman close(fd2); 55019872Swollman } else { 55119872Swollman if (access(filename, R_OK) != 0) { 55219872Swollman asprintf(&msg, "Cannot access %s: %s", 55319872Swollman filename, strerror(errno)); 55419872Swollman dialog_mesgbox("Error", msg, 8, 72); 55519872Swollman free(msg); 55619872Swollman return DITEM_FAILURE | DITEM_RECREATE; 55719872Swollman } 55819872Swollman unlink(_PATH_LOCALTIME); 55919872Swollman if (symlink(filename, _PATH_LOCALTIME) < 0) { 56019872Swollman asprintf(&msg, "Cannot create symbolic link " 56119872Swollman _PATH_LOCALTIME " to %s: %s", 56219872Swollman filename, strerror(errno)); 56319872Swollman dialog_mesgbox("Error", msg, 8, 72); 56419872Swollman free(msg); 56519872Swollman return DITEM_FAILURE | DITEM_RECREATE; 56619872Swollman } 56719872Swollman } 56819872Swollman } 56919872Swollman 57021915Sjkh#ifdef VERBOSE 57119872Swollman if (copymode) 57219872Swollman asprintf(&msg, "Copied timezone file from %s to " 57319872Swollman _PATH_LOCALTIME, filename); 57419872Swollman else 57519872Swollman asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 57619872Swollman " to %s", filename); 57719872Swollman 57819872Swollman dialog_mesgbox("Done", msg, 8, 72); 57919872Swollman free(msg); 58021915Sjkh#endif 58119872Swollman return DITEM_LEAVE_MENU; 58219872Swollman} 58319872Swollman 58419872Swollmanstatic int 58519872Swollmanconfirm_zone(const char *filename) 58619872Swollman{ 58719872Swollman char *msg; 58819872Swollman struct tm *tm; 58919872Swollman time_t t = time(0); 59019872Swollman int rv; 59119872Swollman 59219872Swollman setenv("TZ", filename, 1); 59319872Swollman tzset(); 59419872Swollman tm = localtime(&t); 59519872Swollman 59619872Swollman asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 59719872Swollman tm->tm_zone); 59819872Swollman rv = !dialog_yesno("Confirmation", msg, 4, 72); 59919872Swollman free(msg); 60019872Swollman return rv; 60119872Swollman} 60219872Swollman 60319872Swollmanstatic int 60419872Swollmanset_zone_multi(dialogMenuItem *dmi) 60519872Swollman{ 60619872Swollman char *fn; 60719872Swollman struct zone *zp = dmi->data; 60819872Swollman int rv; 60919872Swollman 61019872Swollman if (!confirm_zone(zp->filename)) 61119872Swollman return DITEM_FAILURE | DITEM_RECREATE; 61219872Swollman 61319872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 61419872Swollman rv = install_zone_file(fn); 61519872Swollman free(fn); 61619872Swollman return rv; 61719872Swollman} 61819872Swollman 61919872Swollmanstatic int 62019872Swollmanset_zone_whole_country(dialogMenuItem *dmi) 62119872Swollman{ 62219872Swollman char *fn; 62319872Swollman struct country *cp = dmi->data; 62419872Swollman int rv; 62519872Swollman 62619872Swollman if (!confirm_zone(cp->filename)) 62719872Swollman return DITEM_FAILURE | DITEM_RECREATE; 62819872Swollman 62919872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 63019872Swollman rv = install_zone_file(fn); 63119872Swollman free(fn); 63219872Swollman return rv; 63319872Swollman} 63419872Swollman 63530763Scharnierstatic void 63630763Scharnierusage() 63730763Scharnier{ 63830763Scharnier fprintf(stderr, "usage: tzsetup [-n]\n"); 63930763Scharnier exit(1); 64030763Scharnier} 64130763Scharnier 64219872Swollmanint 64319872Swollmanmain(int argc, char **argv) 64419872Swollman{ 64541852Speter int c, fd; 64619872Swollman 64719872Swollman while ((c = getopt(argc, argv, "n")) != -1) { 64819872Swollman switch(c) { 64919872Swollman case 'n': 65019872Swollman reallydoit = 0; 65119872Swollman break; 65219872Swollman 65319872Swollman default: 65430763Scharnier usage(); 65519872Swollman } 65619872Swollman } 65719872Swollman 65843544Swollman if (argc - optind > 1) 65930763Scharnier usage(); 66019872Swollman 66149435Sru /* Override the user-supplied umask. */ 66249435Sru (void)umask(S_IWGRP|S_IWOTH); 66349435Sru 66419872Swollman read_iso3166_table(); 66519872Swollman read_zones(); 66619872Swollman sort_countries(); 66719872Swollman make_menus(); 66819872Swollman 66919872Swollman init_dialog(); 67070092Sjkh if (!dialog_noyes("Select local or UTC (Greenwich Mean Time) clock", 67122815Sjkh "Is this machine's CMOS clock set to UTC? If it is set to local time,\n" 67248121Smharo "or you don't know, please choose NO here!", 7, 72)) { 67330763Scharnier if (reallydoit) 67441852Speter unlink(_PATH_WALL_CMOS_CLOCK); 67532394Ssteve } else { 67641852Speter if (reallydoit) { 67741852Speter fd = open(_PATH_WALL_CMOS_CLOCK, 67849435Sru O_WRONLY|O_CREAT|O_TRUNC, 67949435Sru S_IRUSR|S_IRGRP|S_IROTH); 68041852Speter if (fd < 0) 68141852Speter err(1, "create %s", _PATH_WALL_CMOS_CLOCK); 68241852Speter close(fd); 68341852Speter } 68432394Ssteve } 68522815Sjkh dialog_clear_norefresh(); 68643544Swollman if (optind == argc - 1) { 68743544Swollman char *msg; 68843544Swollman asprintf(&msg, "\nUse the default `%s' zone?", argv[optind]); 68943544Swollman if (!dialog_yesno("Default timezone provided", msg, 7, 72)) { 69043544Swollman install_zone_file(argv[optind]); 69143544Swollman dialog_clear(); 69243544Swollman end_dialog(); 69343544Swollman return 0; 69443544Swollman } 69543544Swollman free(msg); 69643544Swollman dialog_clear_norefresh(); 69743544Swollman } 69819872Swollman dialog_menu("Time Zone Selector", "Select a region", -1, -1, 69919887Sjoerg NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 70043544Swollman 70122815Sjkh dialog_clear(); 70219872Swollman end_dialog(); 70319872Swollman return 0; 70419872Swollman} 70519872Swollman 706