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. 15179530Sjkim * 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 35179530Sjkim#include <sys/cdefs.h> 36179530Sjkim__FBSDID("$FreeBSD: stable/10/usr.sbin/tzsetup/tzsetup.c 338441 2018-09-03 06:57:25Z delphij $"); 3730763Scharnier 3819872Swollman#include <err.h> 3919872Swollman#include <errno.h> 4019872Swollman#include <stdio.h> 4119872Swollman#include <stdlib.h> 4219872Swollman#include <string.h> 4366907Swollman#include <time.h> 4419872Swollman#include <unistd.h> 4519872Swollman 4619872Swollman#include <sys/fcntl.h> 47198267Sedwin#include <sys/param.h> 4819872Swollman#include <sys/queue.h> 4919872Swollman#include <sys/stat.h> 50322096Smarius#include <sys/sysctl.h> 5119872Swollman 52322096Smarius#ifdef HAVE_DIALOG 53227934Sfjoe#include <dialog.h> 54322096Smarius#endif 55227934Sfjoe 56179530Sjkim#define _PATH_ZONETAB "/usr/share/zoneinfo/zone.tab" 57179530Sjkim#define _PATH_ISO3166 "/usr/share/misc/iso3166" 58179530Sjkim#define _PATH_ZONEINFO "/usr/share/zoneinfo" 59179530Sjkim#define _PATH_LOCALTIME "/etc/localtime" 60198267Sedwin#define _PATH_DB "/var/db/zoneinfo" 61179530Sjkim#define _PATH_WALL_CMOS_CLOCK "/etc/wall_cmos_clock" 6219872Swollman 63230005Swollman#ifdef PATH_MAX 64230005Swollman#define SILLY_BUFFER_SIZE 2*PATH_MAX 65230005Swollman#else 66230005Swollman#warning "Somebody needs to fix this to dynamically size this buffer." 67230005Swollman#define SILLY_BUFFER_SIZE 2048 68230005Swollman#endif 69230005Swollman 70227934Sfjoe/* special return codes for `fire' actions */ 71227934Sfjoe#define DITEM_FAILURE 1 72227934Sfjoe 73227934Sfjoe/* flags - returned in upper 16 bits of return status */ 74227934Sfjoe#define DITEM_LEAVE_MENU (1 << 16) 75227934Sfjoe#define DITEM_RECREATE (1 << 18) 76227934Sfjoe 77322096Smariusstatic char path_zonetab[MAXPATHLEN], path_iso3166[MAXPATHLEN], 78322096Smarius path_zoneinfo[MAXPATHLEN], path_localtime[MAXPATHLEN], 79322096Smarius path_db[MAXPATHLEN], path_wall_cmos_clock[MAXPATHLEN]; 80322096Smarius 81322096Smariusstatic int reallydoit = 1; 82322096Smariusstatic int reinstall = 0; 83322096Smariusstatic char *chrootenv = NULL; 84322096Smarius 85322096Smariusstatic void usage(void); 86322096Smariusstatic int install_zoneinfo(const char *zoneinfo); 87322096Smariusstatic int install_zoneinfo_file(const char *zoneinfo_file); 88322096Smarius 89322096Smarius#ifdef HAVE_DIALOG 90227934Sfjoe/* for use in describing more exotic behaviors */ 91227934Sfjoetypedef struct dialogMenuItem { 92227934Sfjoe char *prompt; 93227934Sfjoe char *title; 94227934Sfjoe int (*fire)(struct dialogMenuItem *self); 95227934Sfjoe void *data; 96227934Sfjoe} dialogMenuItem; 97227934Sfjoe 98227934Sfjoestatic int 99228176Sfjoexdialog_count_rows(const char *p) 100228176Sfjoe{ 101228176Sfjoe int rows = 0; 102228176Sfjoe 103228176Sfjoe while ((p = strchr(p, '\n')) != NULL) { 104228176Sfjoe p++; 105228176Sfjoe if (*p == '\0') 106228176Sfjoe break; 107228176Sfjoe rows++; 108228176Sfjoe } 109228176Sfjoe 110322376Smarius return (rows ? rows : 1); 111228176Sfjoe} 112228176Sfjoe 113228176Sfjoestatic int 114228176Sfjoexdialog_count_columns(const char *p) 115228176Sfjoe{ 116228176Sfjoe int len; 117228176Sfjoe int max_len = 0; 118228176Sfjoe const char *q; 119228176Sfjoe 120228176Sfjoe for (; (q = strchr(p, '\n')) != NULL; p = q + 1) { 121228176Sfjoe len = q - p; 122228176Sfjoe max_len = MAX(max_len, len); 123228176Sfjoe } 124228176Sfjoe 125228176Sfjoe len = strlen(p); 126228176Sfjoe max_len = MAX(max_len, len); 127322376Smarius return (max_len); 128228176Sfjoe} 129228176Sfjoe 130228176Sfjoestatic int 131227934Sfjoexdialog_menu(const char *title, const char *cprompt, int height, int width, 132227934Sfjoe int menu_height, int item_no, dialogMenuItem *ditems) 133227934Sfjoe{ 134227947Sfjoe int i, result, choice = 0; 135227934Sfjoe DIALOG_LISTITEM *listitems; 136227934Sfjoe DIALOG_VARS save_vars; 137227934Sfjoe 138227934Sfjoe dlg_save_vars(&save_vars); 139227934Sfjoe 140227934Sfjoe /* initialize list items */ 141227947Sfjoe listitems = dlg_calloc(DIALOG_LISTITEM, item_no + 1); 142227934Sfjoe assert_ptr(listitems, "xdialog_menu"); 143227934Sfjoe for (i = 0; i < item_no; i++) { 144227934Sfjoe listitems[i].name = ditems[i].prompt; 145227934Sfjoe listitems[i].text = ditems[i].title; 146227934Sfjoe } 147227934Sfjoe 148228176Sfjoe /* calculate height */ 149228176Sfjoe if (height < 0) 150228176Sfjoe height = xdialog_count_rows(cprompt) + menu_height + 4 + 2; 151228176Sfjoe if (height > LINES) 152228176Sfjoe height = LINES; 153228176Sfjoe 154227934Sfjoe /* calculate width */ 155227934Sfjoe if (width < 0) { 156227934Sfjoe int tag_x = 0; 157227934Sfjoe 158227934Sfjoe for (i = 0; i < item_no; i++) { 159227934Sfjoe int j, l; 160227934Sfjoe 161227934Sfjoe l = strlen(listitems[i].name); 162227934Sfjoe for (j = 0; j < item_no; j++) { 163227934Sfjoe int k = strlen(listitems[j].text); 164227934Sfjoe tag_x = MAX(tag_x, l + k + 2); 165227934Sfjoe } 166227934Sfjoe } 167322376Smarius width = MAX(xdialog_count_columns(cprompt), title != NULL ? 168322376Smarius xdialog_count_columns(title) : 0); 169227934Sfjoe width = MAX(width, tag_x + 4) + 4; 170227934Sfjoe } 171227934Sfjoe width = MAX(width, 24); 172227934Sfjoe if (width > COLS) 173227934Sfjoe width = COLS; 174227934Sfjoe 175227934Sfjoeagain: 176227947Sfjoe dialog_vars.default_item = listitems[choice].name; 177227934Sfjoe result = dlg_menu(title, cprompt, height, width, 178227934Sfjoe menu_height, item_no, listitems, &choice, NULL); 179227934Sfjoe switch (result) { 180227934Sfjoe case DLG_EXIT_ESC: 181227934Sfjoe result = -1; 182227934Sfjoe break; 183227934Sfjoe case DLG_EXIT_OK: 184227934Sfjoe if (ditems[choice].fire != NULL) { 185227934Sfjoe int status; 186227934Sfjoe 187227934Sfjoe status = ditems[choice].fire(ditems + choice); 188227934Sfjoe if (status & DITEM_RECREATE) { 189227934Sfjoe dlg_clear(); 190227934Sfjoe goto again; 191227934Sfjoe } 192227934Sfjoe } 193227934Sfjoe result = 0; 194227934Sfjoe break; 195227934Sfjoe case DLG_EXIT_CANCEL: 196227934Sfjoe default: 197227934Sfjoe result = 1; 198227934Sfjoe break; 199227934Sfjoe } 200227934Sfjoe 201227934Sfjoe free(listitems); 202227934Sfjoe dlg_restore_vars(&save_vars); 203322376Smarius return (result); 204227934Sfjoe} 205227934Sfjoe 206198350Sedwinstatic int usedialog = 1; 20719872Swollman 208220172Sedwinstatic int confirm_zone(const char *filename); 209179530Sjkimstatic int continent_country_menu(dialogMenuItem *); 210179530Sjkimstatic int set_zone_multi(dialogMenuItem *); 211179530Sjkimstatic int set_zone_whole_country(dialogMenuItem *); 212179530Sjkimstatic int set_zone_menu(dialogMenuItem *); 213220172Sedwinstatic int set_zone_utc(void); 21419872Swollman 21519872Swollmanstruct continent { 21619872Swollman dialogMenuItem *menu; 217179530Sjkim int nitems; 21819872Swollman}; 21919872Swollman 220179530Sjkimstatic struct continent africa, america, antarctica, arctic, asia, atlantic; 221220172Sedwinstatic struct continent australia, europe, indian, pacific, utc; 22219872Swollman 22319872Swollmanstatic struct continent_names { 224179530Sjkim const char *name; 22519872Swollman struct continent *continent; 22619872Swollman} continent_names[] = { 227179530Sjkim { "Africa", &africa }, 228179530Sjkim { "America", &america }, 229179530Sjkim { "Antarctica", &antarctica }, 230179530Sjkim { "Arctic", &arctic }, 231179530Sjkim { "Asia", &asia }, 232179530Sjkim { "Atlantic", &atlantic }, 233179530Sjkim { "Australia", &australia }, 234179530Sjkim { "Europe", &europe }, 235179530Sjkim { "Indian", &indian }, 236220172Sedwin { "Pacific", &pacific }, 237227934Sfjoe { "UTC", &utc } 23819872Swollman}; 23919872Swollman 240179530Sjkimstatic struct continent_items { 241179530Sjkim char prompt[2]; 242179530Sjkim char title[30]; 243179530Sjkim} continent_items[] = { 244179530Sjkim { "1", "Africa" }, 245179530Sjkim { "2", "America -- North and South" }, 246179530Sjkim { "3", "Antarctica" }, 247179530Sjkim { "4", "Arctic Ocean" }, 248179530Sjkim { "5", "Asia" }, 249179530Sjkim { "6", "Atlantic Ocean" }, 250179530Sjkim { "7", "Australia" }, 251179530Sjkim { "8", "Europe" }, 252179530Sjkim { "9", "Indian Ocean" }, 253220172Sedwin { "0", "Pacific Ocean" }, 254220172Sedwin { "a", "UTC" } 25519872Swollman}; 25619872Swollman 257179530Sjkim#define NCONTINENTS \ 258179530Sjkim (int)((sizeof(continent_items)) / (sizeof(continent_items[0]))) 259179530Sjkimstatic dialogMenuItem continents[NCONTINENTS]; 260179530Sjkim 261179530Sjkim#define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9) 262179530Sjkim 26319872Swollmanstatic int 26419872Swollmancontinent_country_menu(dialogMenuItem *continent) 26519872Swollman{ 266179530Sjkim char title[64], prompt[64]; 26719872Swollman struct continent *contp = continent->data; 268179530Sjkim int isocean = OCEANP(continent - continents); 269179530Sjkim int menulen; 270179530Sjkim int rv; 27119872Swollman 272220172Sedwin if (strcmp(continent->title, "UTC") == 0) 273322376Smarius return (set_zone_utc()); 274220172Sedwin 27519872Swollman /* Short cut -- if there's only one country, don't post a menu. */ 276179497Sjkim if (contp->nitems == 1) 277179497Sjkim return (contp->menu[0].fire(&contp->menu[0])); 27819872Swollman 27919872Swollman /* It's amazing how much good grammar really matters... */ 280179530Sjkim if (!isocean) { 281179530Sjkim snprintf(title, sizeof(title), "Countries in %s", 282179530Sjkim continent->title); 283179530Sjkim snprintf(prompt, sizeof(prompt), "Select a country or region"); 284179530Sjkim } else { 285179530Sjkim snprintf(title, sizeof(title), "Islands and groups in the %s", 286179530Sjkim continent->title); 287179530Sjkim snprintf(prompt, sizeof(prompt), "Select an island or group"); 288179530Sjkim } 28919872Swollman 29019872Swollman menulen = contp->nitems < 16 ? contp->nitems : 16; 291227934Sfjoe rv = xdialog_menu(title, prompt, -1, -1, menulen, contp->nitems, 292227934Sfjoe contp->menu); 29319872Swollman if (rv == 0) 294179530Sjkim return (DITEM_LEAVE_MENU); 295179530Sjkim return (DITEM_RECREATE); 29619872Swollman} 29719872Swollman 29819872Swollmanstatic struct continent * 29919872Swollmanfind_continent(const char *name) 30019872Swollman{ 301179530Sjkim int i; 30219872Swollman 303179530Sjkim for (i = 0; i < NCONTINENTS; i++) 30419872Swollman if (strcmp(name, continent_names[i].name) == 0) 305179530Sjkim return (continent_names[i].continent); 306179530Sjkim return (0); 30719872Swollman} 30819872Swollman 30919872Swollmanstruct country { 310179530Sjkim char *name; 311179530Sjkim char *tlc; 312179530Sjkim int nzones; 313179530Sjkim char *filename; /* use iff nzones < 0 */ 314179530Sjkim struct continent *continent; /* use iff nzones < 0 */ 315179530Sjkim TAILQ_HEAD(, zone) zones; /* use iff nzones > 0 */ 316179530Sjkim dialogMenuItem *submenu; /* use iff nzones > 0 */ 31719872Swollman}; 31819872Swollman 31919872Swollmanstruct zone { 32060938Sjake TAILQ_ENTRY(zone) link; 321179530Sjkim char *descr; 322179530Sjkim char *filename; 32319872Swollman struct continent *continent; 32419872Swollman}; 32519872Swollman 32619872Swollman/* 32719872Swollman * This is the easiest organization... we use ISO 3166 country codes, 32819872Swollman * of the two-letter variety, so we just size this array to suit. 32919872Swollman * Beats worrying about dynamic allocation. 33019872Swollman */ 331179530Sjkim#define NCOUNTRIES (26 * 26) 33222181Sjhaystatic struct country countries[NCOUNTRIES]; 33319872Swollman 334179530Sjkim#define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A')) 335179530Sjkim 33619872Swollman/* 33719872Swollman * Read the ISO 3166 country code database in _PATH_ISO3166 33819872Swollman * (/usr/share/misc/iso3166). On error, exit via err(3). 33919872Swollman */ 34019872Swollmanstatic void 34119872Swollmanread_iso3166_table(void) 34219872Swollman{ 343179530Sjkim FILE *fp; 344179530Sjkim struct country *cp; 345179530Sjkim size_t len; 346179530Sjkim char *s, *t, *name; 347179530Sjkim int lineno; 34819872Swollman 349198350Sedwin fp = fopen(path_iso3166, "r"); 35019872Swollman if (!fp) 351209190Semaste err(1, "%s", path_iso3166); 35219872Swollman lineno = 0; 35319872Swollman 354321895Smarius while ((s = fgetln(fp, &len)) != NULL) { 35519872Swollman lineno++; 35619872Swollman if (s[len - 1] != '\n') 357198350Sedwin errx(1, "%s:%d: invalid format", path_iso3166, lineno); 35819872Swollman s[len - 1] = '\0'; 35930999Sjoerg if (s[0] == '#' || strspn(s, " \t") == len - 1) 36019872Swollman continue; 36119872Swollman 36219872Swollman /* Isolate the two-letter code. */ 36319872Swollman t = strsep(&s, "\t"); 364321895Smarius if (t == NULL || strlen(t) != 2) 365198350Sedwin errx(1, "%s:%d: invalid format", path_iso3166, lineno); 36619872Swollman if (t[0] < 'A' || t[0] > 'Z' || t[1] < 'A' || t[1] > 'Z') 367198350Sedwin errx(1, "%s:%d: invalid code `%s'", path_iso3166, 368179530Sjkim lineno, t); 36919872Swollman 37019872Swollman /* Now skip past the three-letter and numeric codes. */ 371179530Sjkim name = strsep(&s, "\t"); /* 3-let */ 372321895Smarius if (name == NULL || strlen(name) != 3) 373198350Sedwin errx(1, "%s:%d: invalid format", path_iso3166, lineno); 374179530Sjkim name = strsep(&s, "\t"); /* numeric */ 375321895Smarius if (name == NULL || strlen(name) != 3) 376198350Sedwin errx(1, "%s:%d: invalid format", path_iso3166, lineno); 37719872Swollman 37819872Swollman name = s; 37919872Swollman 38019872Swollman cp = &countries[CODE2INT(t)]; 38119872Swollman if (cp->name) 382198350Sedwin errx(1, "%s:%d: country code `%s' multiply defined: %s", 383198350Sedwin path_iso3166, lineno, t, cp->name); 38419872Swollman cp->name = strdup(name); 38556487Scharnier if (cp->name == NULL) 38656487Scharnier errx(1, "malloc failed"); 38719872Swollman cp->tlc = strdup(t); 38856487Scharnier if (cp->tlc == NULL) 38956487Scharnier errx(1, "malloc failed"); 39019872Swollman } 39119872Swollman 39219872Swollman fclose(fp); 39319872Swollman} 39419872Swollman 39519872Swollmanstatic void 39619872Swollmanadd_zone_to_country(int lineno, const char *tlc, const char *descr, 397179530Sjkim const char *file, struct continent *cont) 39819872Swollman{ 399179530Sjkim struct zone *zp; 400179530Sjkim struct country *cp; 40119872Swollman 40219872Swollman if (tlc[0] < 'A' || tlc[0] > 'Z' || tlc[1] < 'A' || tlc[1] > 'Z') 403198350Sedwin errx(1, "%s:%d: country code `%s' invalid", path_zonetab, 404179530Sjkim lineno, tlc); 405227934Sfjoe 40619872Swollman cp = &countries[CODE2INT(tlc)]; 40719872Swollman if (cp->name == 0) 408198350Sedwin errx(1, "%s:%d: country code `%s' unknown", path_zonetab, 409179530Sjkim lineno, tlc); 41019872Swollman 41119872Swollman if (descr) { 41219872Swollman if (cp->nzones < 0) 413198350Sedwin errx(1, "%s:%d: conflicting zone definition", 414198350Sedwin path_zonetab, lineno); 41519872Swollman 416179530Sjkim zp = malloc(sizeof(*zp)); 417321895Smarius if (zp == NULL) 418179530Sjkim errx(1, "malloc(%zu)", sizeof(*zp)); 419227934Sfjoe 42019872Swollman if (cp->nzones == 0) 42119872Swollman TAILQ_INIT(&cp->zones); 42219872Swollman 42319872Swollman zp->descr = strdup(descr); 42456487Scharnier if (zp->descr == NULL) 42556487Scharnier errx(1, "malloc failed"); 42619872Swollman zp->filename = strdup(file); 42756487Scharnier if (zp->filename == NULL) 42856487Scharnier errx(1, "malloc failed"); 42919872Swollman zp->continent = cont; 43019872Swollman TAILQ_INSERT_TAIL(&cp->zones, zp, link); 43119872Swollman cp->nzones++; 43219872Swollman } else { 43319872Swollman if (cp->nzones > 0) 434198350Sedwin errx(1, "%s:%d: zone must have description", 435198350Sedwin path_zonetab, lineno); 43619872Swollman if (cp->nzones < 0) 437198350Sedwin errx(1, "%s:%d: zone multiply defined", 438198350Sedwin path_zonetab, lineno); 43919872Swollman cp->nzones = -1; 44019872Swollman cp->filename = strdup(file); 44156487Scharnier if (cp->filename == NULL) 44256487Scharnier errx(1, "malloc failed"); 44319872Swollman cp->continent = cont; 44419872Swollman } 44519872Swollman} 44619872Swollman 44719872Swollman/* 44819872Swollman * This comparison function intentionally sorts all of the null-named 44919872Swollman * ``countries''---i.e., the codes that don't correspond to a real 45019872Swollman * country---to the end. Everything else is lexical by country name. 45119872Swollman */ 45219872Swollmanstatic int 45319872Swollmancompare_countries(const void *xa, const void *xb) 45419872Swollman{ 45519872Swollman const struct country *a = xa, *b = xb; 45619872Swollman 45719872Swollman if (a->name == 0 && b->name == 0) 458179530Sjkim return (0); 45919872Swollman if (a->name == 0 && b->name != 0) 460179530Sjkim return (1); 46119872Swollman if (b->name == 0) 462179530Sjkim return (-1); 46319872Swollman 464179530Sjkim return (strcmp(a->name, b->name)); 46519872Swollman} 46619872Swollman 46719872Swollman/* 46819872Swollman * This must be done AFTER all zone descriptions are read, since it breaks 46919872Swollman * CODE2INT(). 47019872Swollman */ 47119872Swollmanstatic void 47219872Swollmansort_countries(void) 47319872Swollman{ 474179530Sjkim 475179530Sjkim qsort(countries, NCOUNTRIES, sizeof(countries[0]), compare_countries); 47619872Swollman} 47719872Swollman 47819872Swollmanstatic void 47919872Swollmanread_zones(void) 48019872Swollman{ 481179530Sjkim char contbuf[16]; 482179530Sjkim FILE *fp; 48319872Swollman struct continent *cont; 484338441Sdelphij size_t len, contlen; 485321895Smarius char *line, *tlc, *file, *descr, *p; 486179530Sjkim int lineno; 48719872Swollman 488198350Sedwin fp = fopen(path_zonetab, "r"); 48919872Swollman if (!fp) 490209190Semaste err(1, "%s", path_zonetab); 49119872Swollman lineno = 0; 49219872Swollman 493321895Smarius while ((line = fgetln(fp, &len)) != NULL) { 49419872Swollman lineno++; 49519872Swollman if (line[len - 1] != '\n') 496198350Sedwin errx(1, "%s:%d: invalid format", path_zonetab, lineno); 49719872Swollman line[len - 1] = '\0'; 49819872Swollman if (line[0] == '#') 49919872Swollman continue; 50019872Swollman 50119872Swollman tlc = strsep(&line, "\t"); 50219872Swollman if (strlen(tlc) != 2) 503198350Sedwin errx(1, "%s:%d: invalid country code `%s'", 504198350Sedwin path_zonetab, lineno, tlc); 505321895Smarius /* coord = */ strsep(&line, "\t"); /* Unused */ 50619872Swollman file = strsep(&line, "\t"); 507338441Sdelphij /* get continent portion from continent/country */ 50819872Swollman p = strchr(file, '/'); 509321895Smarius if (p == NULL) 510198350Sedwin errx(1, "%s:%d: invalid zone name `%s'", path_zonetab, 511179530Sjkim lineno, file); 512338441Sdelphij contlen = p - file + 1; /* trailing nul */ 513338441Sdelphij if (contlen > sizeof(contbuf)) 514338441Sdelphij errx(1, "%s:%d: continent name in zone name `%s' too long", 515338441Sdelphij path_zonetab, lineno, file); 516338441Sdelphij strlcpy(contbuf, file, contlen); 51719872Swollman cont = find_continent(contbuf); 51819872Swollman if (!cont) 519198350Sedwin errx(1, "%s:%d: invalid region `%s'", path_zonetab, 520179530Sjkim lineno, contbuf); 52119872Swollman 522179530Sjkim descr = (line != NULL && *line != '\0') ? line : NULL; 52319872Swollman 52419872Swollman add_zone_to_country(lineno, tlc, descr, file, cont); 52519872Swollman } 52619872Swollman fclose(fp); 52719872Swollman} 52819872Swollman 52919872Swollmanstatic void 53019872Swollmanmake_menus(void) 53119872Swollman{ 532179530Sjkim struct country *cp; 533179530Sjkim struct zone *zp, *zp2; 53419872Swollman struct continent *cont; 535179530Sjkim dialogMenuItem *dmi; 536179530Sjkim int i; 53719872Swollman 53819872Swollman /* 53919872Swollman * First, count up all the countries in each continent/ocean. 54019872Swollman * Be careful to count those countries which have multiple zones 54119872Swollman * only once for each. NB: some countries are in multiple 54219872Swollman * continents/oceans. 54319872Swollman */ 54419872Swollman for (cp = countries; cp->name; cp++) { 54519872Swollman if (cp->nzones == 0) 54619872Swollman continue; 54719872Swollman if (cp->nzones < 0) { 54819872Swollman cp->continent->nitems++; 54919872Swollman } else { 55070486Sben TAILQ_FOREACH(zp, &cp->zones, link) { 55119872Swollman cont = zp->continent; 55270486Sben for (zp2 = TAILQ_FIRST(&cp->zones); 553179530Sjkim zp2->continent != cont; 554179530Sjkim zp2 = TAILQ_NEXT(zp2, link)) 55519872Swollman ; 55619872Swollman if (zp2 == zp) 55719872Swollman zp->continent->nitems++; 55819872Swollman } 55919872Swollman } 56019872Swollman } 56119872Swollman 56219872Swollman /* 563179530Sjkim * Now allocate memory for the country menus and initialize 564179530Sjkim * continent menus. We set nitems back to zero so that we can 565179530Sjkim * use it for counting again when we actually build the menus. 56619872Swollman */ 567179530Sjkim memset(continents, 0, sizeof(continents)); 56819872Swollman for (i = 0; i < NCONTINENTS; i++) { 56919872Swollman continent_names[i].continent->menu = 570179530Sjkim malloc(sizeof(dialogMenuItem) * 571179530Sjkim continent_names[i].continent->nitems); 572321895Smarius if (continent_names[i].continent->menu == NULL) 57356487Scharnier errx(1, "malloc for continent menu"); 57419872Swollman continent_names[i].continent->nitems = 0; 575179530Sjkim continents[i].prompt = continent_items[i].prompt; 576179530Sjkim continents[i].title = continent_items[i].title; 577179530Sjkim continents[i].fire = continent_country_menu; 578179530Sjkim continents[i].data = continent_names[i].continent; 57919872Swollman } 58019872Swollman 58119872Swollman /* 58219872Swollman * Now that memory is allocated, create the menu items for 58319872Swollman * each continent. For multiple-zone countries, also create 58419872Swollman * the country's zone submenu. 58519872Swollman */ 58619872Swollman for (cp = countries; cp->name; cp++) { 58719872Swollman if (cp->nzones == 0) 58819872Swollman continue; 58919872Swollman if (cp->nzones < 0) { 59019872Swollman dmi = &cp->continent->menu[cp->continent->nitems]; 591179530Sjkim memset(dmi, 0, sizeof(*dmi)); 592179530Sjkim asprintf(&dmi->prompt, "%d", ++cp->continent->nitems); 59319872Swollman dmi->title = cp->name; 59419872Swollman dmi->fire = set_zone_whole_country; 59519872Swollman dmi->data = cp; 59619872Swollman } else { 597179530Sjkim cp->submenu = malloc(cp->nzones * sizeof(*dmi)); 59819872Swollman if (cp->submenu == 0) 59956487Scharnier errx(1, "malloc for submenu"); 60019872Swollman cp->nzones = 0; 60170486Sben TAILQ_FOREACH(zp, &cp->zones, link) { 60219872Swollman cont = zp->continent; 60319872Swollman dmi = &cp->submenu[cp->nzones]; 604179530Sjkim memset(dmi, 0, sizeof(*dmi)); 605179530Sjkim asprintf(&dmi->prompt, "%d", ++cp->nzones); 60619872Swollman dmi->title = zp->descr; 60719872Swollman dmi->fire = set_zone_multi; 60819872Swollman dmi->data = zp; 60919872Swollman 61070486Sben for (zp2 = TAILQ_FIRST(&cp->zones); 611179530Sjkim zp2->continent != cont; 612179530Sjkim zp2 = TAILQ_NEXT(zp2, link)) 61319872Swollman ; 61419872Swollman if (zp2 != zp) 61519872Swollman continue; 61619872Swollman 61719872Swollman dmi = &cont->menu[cont->nitems]; 618179530Sjkim memset(dmi, 0, sizeof(*dmi)); 61919872Swollman asprintf(&dmi->prompt, "%d", ++cont->nitems); 62019872Swollman dmi->title = cp->name; 62119872Swollman dmi->fire = set_zone_menu; 62219872Swollman dmi->data = cp; 62319872Swollman } 62419872Swollman } 62519872Swollman } 62619872Swollman} 62719872Swollman 62819872Swollmanstatic int 62919872Swollmanset_zone_menu(dialogMenuItem *dmi) 63019872Swollman{ 631179530Sjkim char title[64], prompt[64]; 632179530Sjkim struct country *cp = dmi->data; 633179530Sjkim int menulen; 634179530Sjkim int rv; 63519872Swollman 636179530Sjkim snprintf(title, sizeof(title), "%s Time Zones", cp->name); 637179530Sjkim snprintf(prompt, sizeof(prompt), 638179530Sjkim "Select a zone which observes the same time as your locality."); 63919872Swollman menulen = cp->nzones < 16 ? cp->nzones : 16; 640227934Sfjoe rv = xdialog_menu(title, prompt, -1, -1, menulen, cp->nzones, 641227934Sfjoe cp->submenu); 64219872Swollman if (rv != 0) 643179530Sjkim return (DITEM_RECREATE); 644179530Sjkim return (DITEM_LEAVE_MENU); 64519872Swollman} 64619872Swollman 647321895Smariusstatic int 648220172Sedwinset_zone_utc(void) 649220172Sedwin{ 650322376Smarius if (!confirm_zone("UTC")) 651220172Sedwin return (DITEM_FAILURE | DITEM_RECREATE); 652227934Sfjoe 653321895Smarius return (install_zoneinfo("UTC")); 654220172Sedwin} 655220172Sedwin 65619872Swollmanstatic int 657322096Smariusconfirm_zone(const char *filename) 658322096Smarius{ 659322096Smarius char title[64], prompt[64]; 660322096Smarius time_t t = time(0); 661322096Smarius struct tm *tm; 662322096Smarius int rv; 663322096Smarius 664322376Smarius setenv("TZ", filename, 1); 665322096Smarius tzset(); 666322096Smarius tm = localtime(&t); 667322096Smarius 668322096Smarius snprintf(title, sizeof(title), "Confirmation"); 669322096Smarius snprintf(prompt, sizeof(prompt), 670322096Smarius "Does the abbreviation `%s' look reasonable?", tm->tm_zone); 671322096Smarius rv = !dialog_yesno(title, prompt, 5, 72); 672322096Smarius return (rv); 673322096Smarius} 674322096Smarius 675322096Smariusstatic int 676322096Smariusset_zone_multi(dialogMenuItem *dmi) 677322096Smarius{ 678322096Smarius struct zone *zp = dmi->data; 679322096Smarius int rv; 680322096Smarius 681322096Smarius if (!confirm_zone(zp->filename)) 682322096Smarius return (DITEM_FAILURE | DITEM_RECREATE); 683322096Smarius 684322096Smarius rv = install_zoneinfo(zp->filename); 685322096Smarius return (rv); 686322096Smarius} 687322096Smarius 688322096Smariusstatic int 689322096Smariusset_zone_whole_country(dialogMenuItem *dmi) 690322096Smarius{ 691322096Smarius struct country *cp = dmi->data; 692322096Smarius int rv; 693322096Smarius 694322096Smarius if (!confirm_zone(cp->filename)) 695322096Smarius return (DITEM_FAILURE | DITEM_RECREATE); 696322096Smarius 697322096Smarius rv = install_zoneinfo(cp->filename); 698322096Smarius return (rv); 699322096Smarius} 700322096Smarius 701322096Smarius#endif 702322096Smarius 703322096Smariusstatic int 704198350Sedwininstall_zoneinfo_file(const char *zoneinfo_file) 70519872Swollman{ 706179530Sjkim char buf[1024]; 707230005Swollman char title[64], prompt[SILLY_BUFFER_SIZE]; 708179530Sjkim struct stat sb; 709179530Sjkim ssize_t len; 710179530Sjkim int fd1, fd2, copymode; 71119872Swollman 712198350Sedwin if (lstat(path_localtime, &sb) < 0) { 71319872Swollman /* Nothing there yet... */ 71419872Swollman copymode = 1; 715179530Sjkim } else if (S_ISLNK(sb.st_mode)) 71619872Swollman copymode = 0; 71719872Swollman else 71819872Swollman copymode = 1; 71919872Swollman 72021915Sjkh#ifdef VERBOSE 721230299Semaste snprintf(title, sizeof(title), "Info"); 722322376Smarius if (copymode) 723179530Sjkim snprintf(prompt, sizeof(prompt), 724198350Sedwin "Copying %s to %s", zoneinfo_file, path_localtime); 72519872Swollman else 726179530Sjkim snprintf(prompt, sizeof(prompt), 727198350Sedwin "Creating symbolic link %s to %s", 728230299Semaste path_localtime, zoneinfo_file); 729322096Smarius#ifdef HAVE_DIALOG 730198267Sedwin if (usedialog) 731230299Semaste dialog_msgbox(title, prompt, 8, 72, 1); 732198267Sedwin else 733322096Smarius#endif 734198267Sedwin fprintf(stderr, "%s\n", prompt); 73521915Sjkh#endif 73619872Swollman 73719872Swollman if (reallydoit) { 73819872Swollman if (copymode) { 739198350Sedwin fd1 = open(zoneinfo_file, O_RDONLY, 0); 74019872Swollman if (fd1 < 0) { 741179530Sjkim snprintf(title, sizeof(title), "Error"); 742179530Sjkim snprintf(prompt, sizeof(prompt), 743198350Sedwin "Could not open %s: %s", zoneinfo_file, 744179530Sjkim strerror(errno)); 745322096Smarius#ifdef HAVE_DIALOG 746198267Sedwin if (usedialog) 747227934Sfjoe dialog_msgbox(title, prompt, 8, 72, 1); 748198267Sedwin else 749322096Smarius#endif 750198267Sedwin fprintf(stderr, "%s\n", prompt); 751179530Sjkim return (DITEM_FAILURE | DITEM_RECREATE); 75219872Swollman } 75319872Swollman 754231181Swollman if (unlink(path_localtime) < 0 && errno != ENOENT) { 755230005Swollman snprintf(prompt, sizeof(prompt), 756322376Smarius "Could not delete %s: %s", 757230005Swollman path_localtime, strerror(errno)); 758322096Smarius#ifdef HAVE_DIALOG 759230005Swollman if (usedialog) { 760230005Swollman snprintf(title, sizeof(title), "Error"); 761230005Swollman dialog_msgbox(title, prompt, 8, 72, 1); 762230005Swollman } else 763322096Smarius#endif 764230005Swollman fprintf(stderr, "%s\n", prompt); 765230005Swollman return (DITEM_FAILURE | DITEM_RECREATE); 766230005Swollman } 767230005Swollman 768198350Sedwin fd2 = open(path_localtime, O_CREAT | O_EXCL | O_WRONLY, 769179530Sjkim S_IRUSR | S_IRGRP | S_IROTH); 77019872Swollman if (fd2 < 0) { 771179530Sjkim snprintf(title, sizeof(title), "Error"); 772179530Sjkim snprintf(prompt, sizeof(prompt), 773198350Sedwin "Could not open %s: %s", 774198350Sedwin path_localtime, strerror(errno)); 775322096Smarius#ifdef HAVE_DIALOG 776198267Sedwin if (usedialog) 777227934Sfjoe dialog_msgbox(title, prompt, 8, 72, 1); 778198267Sedwin else 779322096Smarius#endif 780198267Sedwin fprintf(stderr, "%s\n", prompt); 781179530Sjkim return (DITEM_FAILURE | DITEM_RECREATE); 78219872Swollman } 78319872Swollman 784179530Sjkim while ((len = read(fd1, buf, sizeof(buf))) > 0) 785208830Sedwin if ((len = write(fd2, buf, len)) < 0) 786208830Sedwin break; 78719872Swollman 78819872Swollman if (len == -1) { 789179530Sjkim snprintf(title, sizeof(title), "Error"); 790179530Sjkim snprintf(prompt, sizeof(prompt), 791198350Sedwin "Error copying %s to %s %s", zoneinfo_file, 792198350Sedwin path_localtime, strerror(errno)); 793322096Smarius#ifdef HAVE_DIALOG 794198267Sedwin if (usedialog) 795227934Sfjoe dialog_msgbox(title, prompt, 8, 72, 1); 796198267Sedwin else 797322096Smarius#endif 798198267Sedwin fprintf(stderr, "%s\n", prompt); 79919872Swollman /* Better to leave none than a corrupt one. */ 800198350Sedwin unlink(path_localtime); 801179530Sjkim return (DITEM_FAILURE | DITEM_RECREATE); 80219872Swollman } 80319872Swollman close(fd1); 80419872Swollman close(fd2); 80519872Swollman } else { 806198350Sedwin if (access(zoneinfo_file, R_OK) != 0) { 807179530Sjkim snprintf(title, sizeof(title), "Error"); 808179530Sjkim snprintf(prompt, sizeof(prompt), 809198350Sedwin "Cannot access %s: %s", zoneinfo_file, 810179530Sjkim strerror(errno)); 811322096Smarius#ifdef HAVE_DIALOG 812198267Sedwin if (usedialog) 813227934Sfjoe dialog_msgbox(title, prompt, 8, 72, 1); 814198267Sedwin else 815322096Smarius#endif 816198267Sedwin fprintf(stderr, "%s\n", prompt); 817179530Sjkim return (DITEM_FAILURE | DITEM_RECREATE); 81819872Swollman } 819231181Swollman if (unlink(path_localtime) < 0 && errno != ENOENT) { 820230005Swollman snprintf(prompt, sizeof(prompt), 821322376Smarius "Could not delete %s: %s", 822230005Swollman path_localtime, strerror(errno)); 823322096Smarius#ifdef HAVE_DIALOG 824230005Swollman if (usedialog) { 825230005Swollman snprintf(title, sizeof(title), "Error"); 826230005Swollman dialog_msgbox(title, prompt, 8, 72, 1); 827230005Swollman } else 828322096Smarius#endif 829230005Swollman fprintf(stderr, "%s\n", prompt); 830230005Swollman return (DITEM_FAILURE | DITEM_RECREATE); 831230005Swollman } 832198350Sedwin if (symlink(zoneinfo_file, path_localtime) < 0) { 833179530Sjkim snprintf(title, sizeof(title), "Error"); 834179530Sjkim snprintf(prompt, sizeof(prompt), 835198350Sedwin "Cannot create symbolic link %s to %s: %s", 836198350Sedwin path_localtime, zoneinfo_file, 837179530Sjkim strerror(errno)); 838322096Smarius#ifdef HAVE_DIALOG 839198267Sedwin if (usedialog) 840227934Sfjoe dialog_msgbox(title, prompt, 8, 72, 1); 841198267Sedwin else 842322096Smarius#endif 843198267Sedwin fprintf(stderr, "%s\n", prompt); 844179530Sjkim return (DITEM_FAILURE | DITEM_RECREATE); 84519872Swollman } 84619872Swollman } 84719872Swollman 84821915Sjkh#ifdef VERBOSE 849230299Semaste snprintf(title, sizeof(title), "Done"); 850230299Semaste if (copymode) 851230299Semaste snprintf(prompt, sizeof(prompt), 852230299Semaste "Copied timezone file from %s to %s", 853230299Semaste zoneinfo_file, path_localtime); 854230299Semaste else 855230299Semaste snprintf(prompt, sizeof(prompt), 856230299Semaste "Created symbolic link from %s to %s", 857230299Semaste zoneinfo_file, path_localtime); 858322096Smarius#ifdef HAVE_DIALOG 859230299Semaste if (usedialog) 860230299Semaste dialog_msgbox(title, prompt, 8, 72, 1); 861230299Semaste else 862322096Smarius#endif 863230299Semaste fprintf(stderr, "%s\n", prompt); 86421915Sjkh#endif 865230299Semaste } /* reallydoit */ 866198267Sedwin 867198350Sedwin return (DITEM_LEAVE_MENU); 868198350Sedwin} 869198350Sedwin 870198350Sedwinstatic int 871198350Sedwininstall_zoneinfo(const char *zoneinfo) 872198350Sedwin{ 873198350Sedwin int rv; 874198350Sedwin FILE *f; 875198350Sedwin char path_zoneinfo_file[MAXPATHLEN]; 876198350Sedwin 877301156Struckman if ((size_t)snprintf(path_zoneinfo_file, sizeof(path_zoneinfo_file), 878301156Struckman "%s/%s", path_zoneinfo, zoneinfo) >= sizeof(path_zoneinfo_file)) 879301156Struckman errx(1, "%s/%s name too long", path_zoneinfo, zoneinfo); 880198350Sedwin rv = install_zoneinfo_file(path_zoneinfo_file); 881198350Sedwin 882198267Sedwin /* Save knowledge for later */ 883230296Semaste if (reallydoit && (rv & DITEM_FAILURE) == 0) { 884230296Semaste if ((f = fopen(path_db, "w")) != NULL) { 885230296Semaste fprintf(f, "%s\n", zoneinfo); 886230296Semaste fclose(f); 887230296Semaste } 888198267Sedwin } 889198267Sedwin 890198350Sedwin return (rv); 89119872Swollman} 89219872Swollman 89330763Scharnierstatic void 894179530Sjkimusage(void) 89530763Scharnier{ 896179530Sjkim 897222139Sru fprintf(stderr, "usage: tzsetup [-nrs] [-C chroot_directory]" 898222139Sru " [zoneinfo_file | zoneinfo_name]\n"); 89930763Scharnier exit(1); 90030763Scharnier} 90130763Scharnier 90219872Swollmanint 90319872Swollmanmain(int argc, char **argv) 90419872Swollman{ 905322096Smarius#ifdef HAVE_DIALOG 906179530Sjkim char title[64], prompt[128]; 907322096Smarius int fd; 908322096Smarius#endif 909322096Smarius int c, rv, skiputc; 910322096Smarius char vm_guest[16] = ""; 911322096Smarius size_t len = sizeof(vm_guest); 91219872Swollman 913195339Sattilio skiputc = 0; 914322096Smarius 915322096Smarius /* Default skiputc to 1 for VM guests */ 916322096Smarius if (sysctlbyname("kern.vm_guest", vm_guest, &len, NULL, 0) == 0 && 917322096Smarius strcmp(vm_guest, "none") != 0) 918322096Smarius skiputc = 1; 919322096Smarius 920198350Sedwin while ((c = getopt(argc, argv, "C:nrs")) != -1) { 92119872Swollman switch(c) { 922198350Sedwin case 'C': 923198350Sedwin chrootenv = optarg; 924198350Sedwin break; 92519872Swollman case 'n': 92619872Swollman reallydoit = 0; 92719872Swollman break; 928198267Sedwin case 'r': 929198267Sedwin reinstall = 1; 930322096Smarius#ifdef HAVE_DIALOG 931198350Sedwin usedialog = 0; 932322096Smarius#endif 933198267Sedwin break; 934195339Sattilio case 's': 935195339Sattilio skiputc = 1; 936195339Sattilio break; 93719872Swollman default: 93830763Scharnier usage(); 93919872Swollman } 94019872Swollman } 94119872Swollman 94243544Swollman if (argc - optind > 1) 94330763Scharnier usage(); 94419872Swollman 945290033Sdelphij if (chrootenv == NULL) { 946290033Sdelphij strcpy(path_zonetab, _PATH_ZONETAB); 947290033Sdelphij strcpy(path_iso3166, _PATH_ISO3166); 948290033Sdelphij strcpy(path_zoneinfo, _PATH_ZONEINFO); 949290033Sdelphij strcpy(path_localtime, _PATH_LOCALTIME); 950290033Sdelphij strcpy(path_db, _PATH_DB); 951290033Sdelphij strcpy(path_wall_cmos_clock, _PATH_WALL_CMOS_CLOCK); 952290033Sdelphij } else { 953290033Sdelphij sprintf(path_zonetab, "%s/%s", chrootenv, _PATH_ZONETAB); 954290033Sdelphij sprintf(path_iso3166, "%s/%s", chrootenv, _PATH_ISO3166); 955290033Sdelphij sprintf(path_zoneinfo, "%s/%s", chrootenv, _PATH_ZONEINFO); 956290033Sdelphij sprintf(path_localtime, "%s/%s", chrootenv, _PATH_LOCALTIME); 957290033Sdelphij sprintf(path_db, "%s/%s", chrootenv, _PATH_DB); 958290033Sdelphij sprintf(path_wall_cmos_clock, "%s/%s", chrootenv, 959290033Sdelphij _PATH_WALL_CMOS_CLOCK); 960198350Sedwin } 961198350Sedwin 96249435Sru /* Override the user-supplied umask. */ 963179530Sjkim (void)umask(S_IWGRP | S_IWOTH); 96449435Sru 965198267Sedwin if (reinstall == 1) { 966198267Sedwin FILE *f; 967230520Semaste char zoneinfo[MAXPATHLEN]; 968198267Sedwin 969198350Sedwin if ((f = fopen(path_db, "r")) != NULL) { 970230520Semaste if (fgets(zoneinfo, sizeof(zoneinfo), f) != NULL) { 971230520Semaste zoneinfo[sizeof(zoneinfo) - 1] = 0; 972230520Semaste if (strlen(zoneinfo) > 0) { 973230520Semaste zoneinfo[strlen(zoneinfo) - 1] = 0; 974230520Semaste rv = install_zoneinfo(zoneinfo); 975198267Sedwin exit(rv & ~DITEM_LEAVE_MENU); 976198267Sedwin } 977198350Sedwin errx(1, "Error reading %s.\n", path_db); 978198267Sedwin } 979198267Sedwin fclose(f); 980198267Sedwin errx(1, 981198267Sedwin "Unable to determine earlier installed zoneinfo " 982230520Semaste "name. Check %s", path_db); 983198267Sedwin } 984198350Sedwin errx(1, "Cannot open %s for reading. Does it exist?", path_db); 985198267Sedwin } 986198267Sedwin 987198350Sedwin /* 988198350Sedwin * If the arguments on the command-line do not specify a file, 989198350Sedwin * then interpret it as a zoneinfo name 990198350Sedwin */ 991198350Sedwin if (optind == argc - 1) { 992198350Sedwin struct stat sb; 993198350Sedwin 994198350Sedwin if (stat(argv[optind], &sb) != 0) { 995322096Smarius#ifdef HAVE_DIALOG 996198350Sedwin usedialog = 0; 997322096Smarius#endif 998198350Sedwin rv = install_zoneinfo(argv[optind]); 999198350Sedwin exit(rv & ~DITEM_LEAVE_MENU); 1000198350Sedwin } 1001198350Sedwin /* FALLTHROUGH */ 1002198350Sedwin } 1003322096Smarius#ifdef HAVE_DIALOG 1004198350Sedwin 1005230520Semaste read_iso3166_table(); 1006230520Semaste read_zones(); 1007230520Semaste sort_countries(); 1008230520Semaste make_menus(); 1009230520Semaste 1010227934Sfjoe init_dialog(stdin, stdout); 1011195339Sattilio if (skiputc == 0) { 1012227934Sfjoe DIALOG_VARS save_vars; 1013227934Sfjoe int yesno; 1014227934Sfjoe 1015195339Sattilio snprintf(title, sizeof(title), 1016195339Sattilio "Select local or UTC (Greenwich Mean Time) clock"); 1017195339Sattilio snprintf(prompt, sizeof(prompt), 1018195339Sattilio "Is this machine's CMOS clock set to UTC? " 1019195339Sattilio "If it is set to local time,\n" 1020195339Sattilio "or you don't know, please choose NO here!"); 1021227934Sfjoe dlg_save_vars(&save_vars); 1022227934Sfjoe#if !defined(__sparc64__) 1023227934Sfjoe dialog_vars.defaultno = TRUE; 1024227934Sfjoe#endif 1025227934Sfjoe yesno = dialog_yesno(title, prompt, 7, 73); 1026227934Sfjoe dlg_restore_vars(&save_vars); 1027227934Sfjoe if (!yesno) { 1028195339Sattilio if (reallydoit) 1029210243Snork unlink(path_wall_cmos_clock); 1030195339Sattilio } else { 1031195339Sattilio if (reallydoit) { 1032210243Snork fd = open(path_wall_cmos_clock, 1033195339Sattilio O_WRONLY | O_CREAT | O_TRUNC, 1034195339Sattilio S_IRUSR | S_IRGRP | S_IROTH); 1035198254Sedwin if (fd < 0) { 1036198254Sedwin end_dialog(); 1037195339Sattilio err(1, "create %s", 1038210243Snork path_wall_cmos_clock); 1039198254Sedwin } 1040195339Sattilio close(fd); 1041195339Sattilio } 104241852Speter } 1043227934Sfjoe dlg_clear(); 104432394Ssteve } 104543544Swollman if (optind == argc - 1) { 1046179530Sjkim snprintf(title, sizeof(title), "Default timezone provided"); 1047179530Sjkim snprintf(prompt, sizeof(prompt), 1048179530Sjkim "\nUse the default `%s' zone?", argv[optind]); 1049179530Sjkim if (!dialog_yesno(title, prompt, 7, 72)) { 1050198350Sedwin rv = install_zoneinfo_file(argv[optind]); 1051227934Sfjoe dlg_clear(); 105243544Swollman end_dialog(); 1053198267Sedwin exit(rv & ~DITEM_LEAVE_MENU); 105443544Swollman } 1055227934Sfjoe dlg_clear(); 105643544Swollman } 1057179530Sjkim snprintf(title, sizeof(title), "Time Zone Selector"); 1058179530Sjkim snprintf(prompt, sizeof(prompt), "Select a region"); 1059227934Sfjoe xdialog_menu(title, prompt, -1, -1, NCONTINENTS, NCONTINENTS, 1060227934Sfjoe continents); 106143544Swollman 1062227934Sfjoe dlg_clear(); 106319872Swollman end_dialog(); 1064322096Smarius#else 1065322096Smarius usage(); 1066322096Smarius#endif 1067179530Sjkim return (0); 106819872Swollman} 1069