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