tzsetup.c revision 70486
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 70486 2000-12-29 18:04:54Z ben $"; 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 { 38170486Sben TAILQ_FOREACH(zp, &cp->zones, link) { 38219872Swollman cont = zp->continent; 38370486Sben for (zp2 = TAILQ_FIRST(&cp->zones); 38419872Swollman zp2->continent != cont; 38570486Sben zp2 = TAILQ_NEXT(zp2, link)) 38619872Swollman ; 38719872Swollman if (zp2 == zp) 38819872Swollman zp->continent->nitems++; 38919872Swollman } 39019872Swollman } 39119872Swollman } 39219872Swollman 39319872Swollman /* 39419872Swollman * Now allocate memory for the country menus. We set 39519872Swollman * nitems back to zero so that we can use it for counting 39619872Swollman * again when we actually build the menus. 39719872Swollman */ 39819872Swollman for (i = 0; i < NCONTINENTS; i++) { 39919872Swollman continent_names[i].continent->menu = 40019872Swollman malloc(sizeof(dialogMenuItem) * 40119872Swollman continent_names[i].continent->nitems); 40219872Swollman if (continent_names[i].continent->menu == 0) 40356487Scharnier errx(1, "malloc for continent menu"); 40419872Swollman continent_names[i].continent->nitems = 0; 40519872Swollman } 40619872Swollman 40719872Swollman /* 40819872Swollman * Now that memory is allocated, create the menu items for 40919872Swollman * each continent. For multiple-zone countries, also create 41019872Swollman * the country's zone submenu. 41119872Swollman */ 41219872Swollman for (cp = countries; cp->name; cp++) { 41319872Swollman if (cp->nzones == 0) 41419872Swollman continue; 41519872Swollman if (cp->nzones < 0) { 41619872Swollman dmi = &cp->continent->menu[cp->continent->nitems]; 41719872Swollman memset(dmi, 0, sizeof *dmi); 41819872Swollman asprintf(&dmi->prompt, "%d", 41919872Swollman ++cp->continent->nitems); 42019872Swollman dmi->title = cp->name; 42119872Swollman dmi->checked = 0; 42219872Swollman dmi->fire = set_zone_whole_country; 42319872Swollman dmi->selected = 0; 42419872Swollman dmi->data = cp; 42519872Swollman } else { 42619872Swollman cp->submenu = malloc(cp->nzones * sizeof *dmi); 42719872Swollman if (cp->submenu == 0) 42856487Scharnier errx(1, "malloc for submenu"); 42919872Swollman cp->nzones = 0; 43070486Sben TAILQ_FOREACH(zp, &cp->zones, link) { 43119872Swollman cont = zp->continent; 43219872Swollman dmi = &cp->submenu[cp->nzones]; 43319872Swollman memset(dmi, 0, sizeof *dmi); 43419872Swollman asprintf(&dmi->prompt, "%d", 43519872Swollman ++cp->nzones); 43619872Swollman dmi->title = zp->descr; 43719872Swollman dmi->checked = 0; 43819872Swollman dmi->fire = set_zone_multi; 43919872Swollman dmi->selected = 0; 44019872Swollman dmi->data = zp; 44119872Swollman 44270486Sben for (zp2 = TAILQ_FIRST(&cp->zones); 44319872Swollman zp2->continent != cont; 44470486Sben zp2 = TAILQ_NEXT(zp2, link)) 44519872Swollman ; 44619872Swollman if (zp2 != zp) 44719872Swollman continue; 44819872Swollman 44919872Swollman dmi = &cont->menu[cont->nitems]; 45019872Swollman memset(dmi, 0, sizeof *dmi); 45119872Swollman asprintf(&dmi->prompt, "%d", ++cont->nitems); 45219872Swollman dmi->title = cp->name; 45319872Swollman dmi->checked = 0; 45419872Swollman dmi->fire = set_zone_menu; 45519872Swollman dmi->selected = 0; 45619872Swollman dmi->data = cp; 45719872Swollman } 45819872Swollman } 45919872Swollman } 46019872Swollman} 46119872Swollman 46219872Swollmanstatic int 46319872Swollmanset_zone_menu(dialogMenuItem *dmi) 46419872Swollman{ 46519872Swollman int rv; 46619872Swollman char buf[256]; 46719872Swollman struct country *cp = dmi->data; 46819872Swollman int menulen; 46919872Swollman 47019872Swollman snprintf(buf, sizeof buf, "%s Time Zones", cp->name); 47119872Swollman menulen = cp->nzones < 16 ? cp->nzones : 16; 47219872Swollman rv = dialog_menu(buf, "Select a zone which observes the same time as " 47319872Swollman "your locality.", -1, -1, menulen, -cp->nzones, 47419872Swollman cp->submenu, 0, 0, 0); 47519872Swollman if (rv != 0) 47619872Swollman return DITEM_RECREATE; 47719872Swollman return DITEM_LEAVE_MENU; 47819872Swollman} 47919872Swollman 48019872Swollmanstatic int 48119872Swollmaninstall_zone_file(const char *filename) 48219872Swollman{ 48319872Swollman struct stat sb; 48419872Swollman int fd1, fd2; 48519872Swollman int copymode; 48619872Swollman char *msg; 48719872Swollman ssize_t len; 48819872Swollman char buf[1024]; 48919872Swollman 49019872Swollman if (lstat(_PATH_LOCALTIME, &sb) < 0) 49119872Swollman /* Nothing there yet... */ 49219872Swollman copymode = 1; 49319872Swollman else if(S_ISLNK(sb.st_mode)) 49419872Swollman copymode = 0; 49519872Swollman else 49619872Swollman copymode = 1; 49719872Swollman 49821915Sjkh#ifdef VERBOSE 49919872Swollman if (copymode) 50019872Swollman asprintf(&msg, "Copying %s to " _PATH_LOCALTIME, filename); 50119872Swollman else 50219872Swollman asprintf(&msg, "Creating symbolic link " _PATH_LOCALTIME 50319872Swollman " to %s", filename); 50419872Swollman 50519872Swollman dialog_notify(msg); 50619872Swollman free(msg); 50721915Sjkh#endif 50819872Swollman 50919872Swollman if (reallydoit) { 51019872Swollman if (copymode) { 51119872Swollman fd1 = open(filename, O_RDONLY, 0); 51219872Swollman if (fd1 < 0) { 51319872Swollman asprintf(&msg, "Could not open %s: %s", 51419872Swollman filename, strerror(errno)); 51519872Swollman dialog_mesgbox("Error", msg, 8, 72); 51619872Swollman free(msg); 51719872Swollman return DITEM_FAILURE | DITEM_RECREATE; 51819872Swollman } 51919872Swollman 52019872Swollman unlink(_PATH_LOCALTIME); 52119872Swollman fd2 = open(_PATH_LOCALTIME, 52249435Sru O_CREAT|O_EXCL|O_WRONLY, 52349435Sru S_IRUSR|S_IRGRP|S_IROTH); 52419872Swollman if (fd2 < 0) { 52519872Swollman asprintf(&msg, "Could not open " 52619872Swollman _PATH_LOCALTIME ": %s", 52719872Swollman strerror(errno)); 52819872Swollman dialog_mesgbox("Error", msg, 8, 72); 52919872Swollman free(msg); 53019872Swollman return DITEM_FAILURE | DITEM_RECREATE; 53119872Swollman } 53219872Swollman 53319872Swollman while ((len = read(fd1, buf, sizeof buf)) > 0) 53419872Swollman len = write(fd2, buf, len); 53519872Swollman 53619872Swollman if (len == -1) { 53719872Swollman asprintf(&msg, "Error copying %s to " 53819872Swollman _PATH_LOCALTIME ": %s", 53949435Sru filename, strerror(errno)); 54019872Swollman dialog_mesgbox("Error", msg, 8, 72); 54119872Swollman free(msg); 54219872Swollman /* Better to leave none than a corrupt one. */ 54319872Swollman unlink(_PATH_LOCALTIME); 54419872Swollman return DITEM_FAILURE | DITEM_RECREATE; 54519872Swollman } 54619872Swollman close(fd1); 54719872Swollman close(fd2); 54819872Swollman } else { 54919872Swollman if (access(filename, R_OK) != 0) { 55019872Swollman asprintf(&msg, "Cannot access %s: %s", 55119872Swollman filename, strerror(errno)); 55219872Swollman dialog_mesgbox("Error", msg, 8, 72); 55319872Swollman free(msg); 55419872Swollman return DITEM_FAILURE | DITEM_RECREATE; 55519872Swollman } 55619872Swollman unlink(_PATH_LOCALTIME); 55719872Swollman if (symlink(filename, _PATH_LOCALTIME) < 0) { 55819872Swollman asprintf(&msg, "Cannot create symbolic link " 55919872Swollman _PATH_LOCALTIME " to %s: %s", 56019872Swollman filename, strerror(errno)); 56119872Swollman dialog_mesgbox("Error", msg, 8, 72); 56219872Swollman free(msg); 56319872Swollman return DITEM_FAILURE | DITEM_RECREATE; 56419872Swollman } 56519872Swollman } 56619872Swollman } 56719872Swollman 56821915Sjkh#ifdef VERBOSE 56919872Swollman if (copymode) 57019872Swollman asprintf(&msg, "Copied timezone file from %s to " 57119872Swollman _PATH_LOCALTIME, filename); 57219872Swollman else 57319872Swollman asprintf(&msg, "Created symbolic link from " _PATH_LOCALTIME 57419872Swollman " to %s", filename); 57519872Swollman 57619872Swollman dialog_mesgbox("Done", msg, 8, 72); 57719872Swollman free(msg); 57821915Sjkh#endif 57919872Swollman return DITEM_LEAVE_MENU; 58019872Swollman} 58119872Swollman 58219872Swollmanstatic int 58319872Swollmanconfirm_zone(const char *filename) 58419872Swollman{ 58519872Swollman char *msg; 58619872Swollman struct tm *tm; 58719872Swollman time_t t = time(0); 58819872Swollman int rv; 58919872Swollman 59019872Swollman setenv("TZ", filename, 1); 59119872Swollman tzset(); 59219872Swollman tm = localtime(&t); 59319872Swollman 59419872Swollman asprintf(&msg, "Does the abbreviation `%s' look reasonable?", 59519872Swollman tm->tm_zone); 59619872Swollman rv = !dialog_yesno("Confirmation", msg, 4, 72); 59719872Swollman free(msg); 59819872Swollman return rv; 59919872Swollman} 60019872Swollman 60119872Swollmanstatic int 60219872Swollmanset_zone_multi(dialogMenuItem *dmi) 60319872Swollman{ 60419872Swollman char *fn; 60519872Swollman struct zone *zp = dmi->data; 60619872Swollman int rv; 60719872Swollman 60819872Swollman if (!confirm_zone(zp->filename)) 60919872Swollman return DITEM_FAILURE | DITEM_RECREATE; 61019872Swollman 61119872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, zp->filename); 61219872Swollman rv = install_zone_file(fn); 61319872Swollman free(fn); 61419872Swollman return rv; 61519872Swollman} 61619872Swollman 61719872Swollmanstatic int 61819872Swollmanset_zone_whole_country(dialogMenuItem *dmi) 61919872Swollman{ 62019872Swollman char *fn; 62119872Swollman struct country *cp = dmi->data; 62219872Swollman int rv; 62319872Swollman 62419872Swollman if (!confirm_zone(cp->filename)) 62519872Swollman return DITEM_FAILURE | DITEM_RECREATE; 62619872Swollman 62719872Swollman asprintf(&fn, "%s/%s", _PATH_ZONEINFO, cp->filename); 62819872Swollman rv = install_zone_file(fn); 62919872Swollman free(fn); 63019872Swollman return rv; 63119872Swollman} 63219872Swollman 63330763Scharnierstatic void 63430763Scharnierusage() 63530763Scharnier{ 63630763Scharnier fprintf(stderr, "usage: tzsetup [-n]\n"); 63730763Scharnier exit(1); 63830763Scharnier} 63930763Scharnier 64019872Swollmanint 64119872Swollmanmain(int argc, char **argv) 64219872Swollman{ 64341852Speter int c, fd; 64419872Swollman 64519872Swollman while ((c = getopt(argc, argv, "n")) != -1) { 64619872Swollman switch(c) { 64719872Swollman case 'n': 64819872Swollman reallydoit = 0; 64919872Swollman break; 65019872Swollman 65119872Swollman default: 65230763Scharnier usage(); 65319872Swollman } 65419872Swollman } 65519872Swollman 65643544Swollman if (argc - optind > 1) 65730763Scharnier usage(); 65819872Swollman 65949435Sru /* Override the user-supplied umask. */ 66049435Sru (void)umask(S_IWGRP|S_IWOTH); 66149435Sru 66219872Swollman read_iso3166_table(); 66319872Swollman read_zones(); 66419872Swollman sort_countries(); 66519872Swollman make_menus(); 66619872Swollman 66719872Swollman init_dialog(); 66870092Sjkh if (!dialog_noyes("Select local or UTC (Greenwich Mean Time) clock", 66922815Sjkh "Is this machine's CMOS clock set to UTC? If it is set to local time,\n" 67048121Smharo "or you don't know, please choose NO here!", 7, 72)) { 67130763Scharnier if (reallydoit) 67241852Speter unlink(_PATH_WALL_CMOS_CLOCK); 67332394Ssteve } else { 67441852Speter if (reallydoit) { 67541852Speter fd = open(_PATH_WALL_CMOS_CLOCK, 67649435Sru O_WRONLY|O_CREAT|O_TRUNC, 67749435Sru S_IRUSR|S_IRGRP|S_IROTH); 67841852Speter if (fd < 0) 67941852Speter err(1, "create %s", _PATH_WALL_CMOS_CLOCK); 68041852Speter close(fd); 68141852Speter } 68232394Ssteve } 68322815Sjkh dialog_clear_norefresh(); 68443544Swollman if (optind == argc - 1) { 68543544Swollman char *msg; 68643544Swollman asprintf(&msg, "\nUse the default `%s' zone?", argv[optind]); 68743544Swollman if (!dialog_yesno("Default timezone provided", msg, 7, 72)) { 68843544Swollman install_zone_file(argv[optind]); 68943544Swollman dialog_clear(); 69043544Swollman end_dialog(); 69143544Swollman return 0; 69243544Swollman } 69343544Swollman free(msg); 69443544Swollman dialog_clear_norefresh(); 69543544Swollman } 69619872Swollman dialog_menu("Time Zone Selector", "Select a region", -1, -1, 69719887Sjoerg NCONTINENTS, -NCONTINENTS, continents, 0, NULL, NULL); 69843544Swollman 69922815Sjkh dialog_clear(); 70019872Swollman end_dialog(); 70119872Swollman return 0; 70219872Swollman} 70319872Swollman 704