2 * Copyright 1996 Massachusetts Institute of Technology
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all
9 * supporting documentation, and that the name of M.I.T. not be used
10 * in advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission. M.I.T. makes
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied
16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: head/usr.sbin/tzsetup/tzsetup.c 247780 2013-03-04 11:34:31Z dteske $
33 * Second attempt at a `tzmenu' program, using the separate description
34 * files provided in newer tzdata releases.
45 #include <sys/fcntl.h>
46 #include <sys/param.h>
47 #include <sys/queue.h>
52 #define _PATH_ZONETAB "/usr/share/zoneinfo/zone.tab"
53 #define _PATH_ISO3166 "/usr/share/misc/iso3166"
54 #define _PATH_ZONEINFO "/usr/share/zoneinfo"
55 #define _PATH_LOCALTIME "/etc/localtime"
56 #define _PATH_DB "/var/db/zoneinfo"
57 #define _PATH_WALL_CMOS_CLOCK "/etc/wall_cmos_clock"
60 #define SILLY_BUFFER_SIZE 2*PATH_MAX
62 #warning "Somebody needs to fix this to dynamically size this buffer."
63 #define SILLY_BUFFER_SIZE 2048
66 /* special return codes for `fire' actions */
67 #define DITEM_FAILURE 1
69 /* flags - returned in upper 16 bits of return status */
70 #define DITEM_LEAVE_MENU (1 << 16)
71 #define DITEM_RECREATE (1 << 18)
73 /* for use in describing more exotic behaviors */
74 typedef struct dialogMenuItem
{
77 int (*fire
)(struct dialogMenuItem
*self
);
82 xdialog_count_rows(const char *p
)
86 while ((p
= strchr(p
, '\n')) != NULL
) {
93 return rows
? rows
: 1;
97 xdialog_count_columns(const char *p
)
103 for (; (q
= strchr(p
, '\n')) != NULL
; p
= q
+ 1) {
105 max_len
= MAX(max_len
, len
);
109 max_len
= MAX(max_len
, len
);
114 xdialog_menu(const char *title
, const char *cprompt
, int height
, int width
,
115 int menu_height
, int item_no
, dialogMenuItem
*ditems
)
117 int i
, result
, choice
= 0;
118 DIALOG_LISTITEM
*listitems
;
119 DIALOG_VARS save_vars
;
121 dlg_save_vars(&save_vars
);
123 /* initialize list items */
124 listitems
= dlg_calloc(DIALOG_LISTITEM
, item_no
+ 1);
125 assert_ptr(listitems
, "xdialog_menu");
126 for (i
= 0; i
< item_no
; i
++) {
127 listitems
[i
].name
= ditems
[i
].prompt
;
128 listitems
[i
].text
= ditems
[i
].title
;
131 /* calculate height */
133 height
= xdialog_count_rows(cprompt
) + menu_height
+ 4 + 2;
137 /* calculate width */
141 for (i
= 0; i
< item_no
; i
++) {
144 l
= strlen(listitems
[i
].name
);
145 for (j
= 0; j
< item_no
; j
++) {
146 int k
= strlen(listitems
[j
].text
);
147 tag_x
= MAX(tag_x
, l
+ k
+ 2);
150 width
= MAX(xdialog_count_columns(cprompt
), title
!= NULL
? xdialog_count_columns(title
) : 0);
151 width
= MAX(width
, tag_x
+ 4) + 4;
153 width
= MAX(width
, 24);
158 dialog_vars
.default_item
= listitems
[choice
].name
;
159 result
= dlg_menu(title
, cprompt
, height
, width
,
160 menu_height
, item_no
, listitems
, &choice
, NULL
);
166 if (ditems
[choice
].fire
!= NULL
) {
169 status
= ditems
[choice
].fire(ditems
+ choice
);
170 if (status
& DITEM_RECREATE
) {
177 case DLG_EXIT_CANCEL
:
184 dlg_restore_vars(&save_vars
);
188 static char path_zonetab
[MAXPATHLEN
], path_iso3166
[MAXPATHLEN
],
189 path_zoneinfo
[MAXPATHLEN
], path_localtime
[MAXPATHLEN
],
190 path_db
[MAXPATHLEN
], path_wall_cmos_clock
[MAXPATHLEN
];
192 static int reallydoit
= 1;
193 static int reinstall
= 0;
194 static int usedialog
= 1;
195 static char *chrootenv
= NULL
;
197 static void usage(void);
198 static int confirm_zone(const char *filename
);
199 static int continent_country_menu(dialogMenuItem
*);
200 static int install_zoneinfo_file(const char *zoneinfo_file
);
201 static int set_zone_multi(dialogMenuItem
*);
202 static int set_zone_whole_country(dialogMenuItem
*);
203 static int set_zone_menu(dialogMenuItem
*);
204 static int set_zone_utc(void);
207 dialogMenuItem
*menu
;
211 static struct continent africa
, america
, antarctica
, arctic
, asia
, atlantic
;
212 static struct continent australia
, europe
, indian
, pacific
, utc
;
214 static struct continent_names
{
216 struct continent
*continent
;
217 } continent_names
[] = {
218 { "Africa", &africa
},
219 { "America", &america
},
220 { "Antarctica", &antarctica
},
221 { "Arctic", &arctic
},
223 { "Atlantic", &atlantic
},
224 { "Australia", &australia
},
225 { "Europe", &europe
},
226 { "Indian", &indian
},
227 { "Pacific", &pacific
},
231 static struct continent_items
{
234 } continent_items
[] = {
236 { "2", "America -- North and South" },
237 { "3", "Antarctica" },
238 { "4", "Arctic Ocean" },
240 { "6", "Atlantic Ocean" },
241 { "7", "Australia" },
243 { "9", "Indian Ocean" },
244 { "0", "Pacific Ocean" },
248 #define NCONTINENTS \
249 (int)((sizeof(continent_items)) / (sizeof(continent_items[0])))
250 static dialogMenuItem continents
[NCONTINENTS
];
252 #define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9)
255 continent_country_menu(dialogMenuItem
*continent
)
257 char title
[64], prompt
[64];
258 struct continent
*contp
= continent
->data
;
259 int isocean
= OCEANP(continent
- continents
);
263 if (strcmp(continent
->title
, "UTC") == 0)
264 return set_zone_utc();
266 /* Short cut -- if there's only one country, don't post a menu. */
267 if (contp
->nitems
== 1)
268 return (contp
->menu
[0].fire(&contp
->menu
[0]));
270 /* It's amazing how much good grammar really matters... */
272 snprintf(title
, sizeof(title
), "Countries in %s",
274 snprintf(prompt
, sizeof(prompt
), "Select a country or region");
276 snprintf(title
, sizeof(title
), "Islands and groups in the %s",
278 snprintf(prompt
, sizeof(prompt
), "Select an island or group");
281 menulen
= contp
->nitems
< 16 ? contp
->nitems
: 16;
282 rv
= xdialog_menu(title
, prompt
, -1, -1, menulen
, contp
->nitems
,
285 return (DITEM_LEAVE_MENU
);
286 return (DITEM_RECREATE
);
289 static struct continent
*
290 find_continent(const char *name
)
294 for (i
= 0; i
< NCONTINENTS
; i
++)
295 if (strcmp(name
, continent_names
[i
].name
) == 0)
296 return (continent_names
[i
].continent
);
304 char *filename
; /* use iff nzones < 0 */
305 struct continent
*continent
; /* use iff nzones < 0 */
306 TAILQ_HEAD(, zone
) zones
; /* use iff nzones > 0 */
307 dialogMenuItem
*submenu
; /* use iff nzones > 0 */
311 TAILQ_ENTRY(zone
) link
;
314 struct continent
*continent
;
318 * This is the easiest organization... we use ISO 3166 country codes,
319 * of the two-letter variety, so we just size this array to suit.
320 * Beats worrying about dynamic allocation.
322 #define NCOUNTRIES (26 * 26)
323 static struct country countries
[NCOUNTRIES
];
325 #define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A'))
328 * Read the ISO 3166 country code database in _PATH_ISO3166
329 * (/usr/share/misc/iso3166). On error, exit via err(3).
332 read_iso3166_table(void)
340 fp
= fopen(path_iso3166
, "r");
342 err(1, "%s", path_iso3166
);
345 while ((s
= fgetln(fp
, &len
)) != NULL
) {
347 if (s
[len
- 1] != '\n')
348 errx(1, "%s:%d: invalid format", path_iso3166
, lineno
);
350 if (s
[0] == '#' || strspn(s
, " \t") == len
- 1)
353 /* Isolate the two-letter code. */
354 t
= strsep(&s
, "\t");
355 if (t
== NULL
|| strlen(t
) != 2)
356 errx(1, "%s:%d: invalid format", path_iso3166
, lineno
);
357 if (t
[0] < 'A' || t
[0] > 'Z' || t
[1] < 'A' || t
[1] > 'Z')
358 errx(1, "%s:%d: invalid code `%s'", path_iso3166
,
363 cp
= &countries
[CODE2INT(t
)];
365 errx(1, "%s:%d: country code `%s' multiply defined: %s",
366 path_iso3166
, lineno
, t
, cp
->name
);
367 cp
->name
= strdup(name
);
368 if (cp
->name
== NULL
)
369 errx(1, "malloc failed");
372 errx(1, "malloc failed");
379 add_zone_to_country(int lineno
, const char *tlc
, const char *descr
,
380 const char *file
, struct continent
*cont
)
385 if (tlc
[0] < 'A' || tlc
[0] > 'Z' || tlc
[1] < 'A' || tlc
[1] > 'Z')
386 errx(1, "%s:%d: country code `%s' invalid", path_zonetab
,
389 cp
= &countries
[CODE2INT(tlc
)];
391 errx(1, "%s:%d: country code `%s' unknown", path_zonetab
,
396 errx(1, "%s:%d: conflicting zone definition",
397 path_zonetab
, lineno
);
399 zp
= malloc(sizeof(*zp
));
401 errx(1, "malloc(%zu)", sizeof(*zp
));
404 TAILQ_INIT(&cp
->zones
);
406 zp
->descr
= strdup(descr
);
407 if (zp
->descr
== NULL
)
408 errx(1, "malloc failed");
409 zp
->filename
= strdup(file
);
410 if (zp
->filename
== NULL
)
411 errx(1, "malloc failed");
412 zp
->continent
= cont
;
413 TAILQ_INSERT_TAIL(&cp
->zones
, zp
, link
);
417 errx(1, "%s:%d: zone must have description",
418 path_zonetab
, lineno
);
420 errx(1, "%s:%d: zone multiply defined",
421 path_zonetab
, lineno
);
423 cp
->filename
= strdup(file
);
424 if (cp
->filename
== NULL
)
425 errx(1, "malloc failed");
426 cp
->continent
= cont
;
431 * This comparison function intentionally sorts all of the null-named
432 * ``countries''---i.e., the codes that don't correspond to a real
433 * country---to the end. Everything else is lexical by country name.
436 compare_countries(const void *xa
, const void *xb
)
438 const struct country
*a
= xa
, *b
= xb
;
440 if (a
->name
== 0 && b
->name
== 0)
442 if (a
->name
== 0 && b
->name
!= 0)
447 return (strcmp(a
->name
, b
->name
));
451 * This must be done AFTER all zone descriptions are read, since it breaks
458 qsort(countries
, NCOUNTRIES
, sizeof(countries
[0]), compare_countries
);
466 struct continent
*cont
;
468 char *line
, *tlc
, *file
, *descr
, *p
;
471 fp
= fopen(path_zonetab
, "r");
473 err(1, "%s", path_zonetab
);
476 while ((line
= fgetln(fp
, &len
)) != NULL
) {
478 if (line
[len
- 1] != '\n')
479 errx(1, "%s:%d: invalid format", path_zonetab
, lineno
);
480 line
[len
- 1] = '\0';
484 tlc
= strsep(&line
, "\t");
485 if (strlen(tlc
) != 2)
486 errx(1, "%s:%d: invalid country code `%s'",
487 path_zonetab
, lineno
, tlc
);
488 strsep(&line
, "\t"); /* coordinates */
489 file
= strsep(&line
, "\t");
490 p
= strchr(file
, '/');
492 errx(1, "%s:%d: invalid zone name `%s'", path_zonetab
,
495 strncat(contbuf
, file
, p
- file
);
496 cont
= find_continent(contbuf
);
498 errx(1, "%s:%d: invalid region `%s'", path_zonetab
,
501 descr
= (line
!= NULL
&& *line
!= '\0') ? line
: NULL
;
503 add_zone_to_country(lineno
, tlc
, descr
, file
, cont
);
512 struct zone
*zp
, *zp2
;
513 struct continent
*cont
;
518 * First, count up all the countries in each continent/ocean.
519 * Be careful to count those countries which have multiple zones
520 * only once for each. NB: some countries are in multiple
523 for (cp
= countries
; cp
->name
; cp
++) {
526 if (cp
->nzones
< 0) {
527 cp
->continent
->nitems
++;
529 TAILQ_FOREACH(zp
, &cp
->zones
, link
) {
530 cont
= zp
->continent
;
531 for (zp2
= TAILQ_FIRST(&cp
->zones
);
532 zp2
->continent
!= cont
;
533 zp2
= TAILQ_NEXT(zp2
, link
))
536 zp
->continent
->nitems
++;
542 * Now allocate memory for the country menus and initialize
543 * continent menus. We set nitems back to zero so that we can
544 * use it for counting again when we actually build the menus.
546 memset(continents
, 0, sizeof(continents
));
547 for (i
= 0; i
< NCONTINENTS
; i
++) {
548 continent_names
[i
].continent
->menu
=
549 malloc(sizeof(dialogMenuItem
) *
550 continent_names
[i
].continent
->nitems
);
551 if (continent_names
[i
].continent
->menu
== NULL
)
552 errx(1, "malloc for continent menu");
553 continent_names
[i
].continent
->nitems
= 0;
554 continents
[i
].prompt
= continent_items
[i
].prompt
;
555 continents
[i
].title
= continent_items
[i
].title
;
556 continents
[i
].fire
= continent_country_menu
;
557 continents
[i
].data
= continent_names
[i
].continent
;
561 * Now that memory is allocated, create the menu items for
562 * each continent. For multiple-zone countries, also create
563 * the country's zone submenu.
565 for (cp
= countries
; cp
->name
; cp
++) {
568 if (cp
->nzones
< 0) {
569 dmi
= &cp
->continent
->menu
[cp
->continent
->nitems
];
570 memset(dmi
, 0, sizeof(*dmi
));
571 asprintf(&dmi
->prompt
, "%d", ++cp
->continent
->nitems
);
572 dmi
->title
= cp
->name
;
573 dmi
->fire
= set_zone_whole_country
;
576 cp
->submenu
= malloc(cp
->nzones
* sizeof(*dmi
));
577 if (cp
->submenu
== 0)
578 errx(1, "malloc for submenu");
580 TAILQ_FOREACH(zp
, &cp
->zones
, link
) {
581 cont
= zp
->continent
;
582 dmi
= &cp
->submenu
[cp
->nzones
];
583 memset(dmi
, 0, sizeof(*dmi
));
584 asprintf(&dmi
->prompt
, "%d", ++cp
->nzones
);
585 dmi
->title
= zp
->descr
;
586 dmi
->fire
= set_zone_multi
;
589 for (zp2
= TAILQ_FIRST(&cp
->zones
);
590 zp2
->continent
!= cont
;
591 zp2
= TAILQ_NEXT(zp2
, link
))
596 dmi
= &cont
->menu
[cont
->nitems
];
597 memset(dmi
, 0, sizeof(*dmi
));
598 asprintf(&dmi
->prompt
, "%d", ++cont
->nitems
);
599 dmi
->title
= cp
->name
;
600 dmi
->fire
= set_zone_menu
;
608 set_zone_menu(dialogMenuItem
*dmi
)
610 char title
[64], prompt
[64];
611 struct country
*cp
= dmi
->data
;
615 snprintf(title
, sizeof(title
), "%s Time Zones", cp
->name
);
616 snprintf(prompt
, sizeof(prompt
),
617 "Select a zone which observes the same time as your locality.");
618 menulen
= cp
->nzones
< 16 ? cp
->nzones
: 16;
619 rv
= xdialog_menu(title
, prompt
, -1, -1, menulen
, cp
->nzones
,
622 return (DITEM_RECREATE
);
623 return (DITEM_LEAVE_MENU
);
629 if (!confirm_zone(NULL
))
630 return (DITEM_FAILURE
| DITEM_RECREATE
);
632 return (install_zoneinfo_file(NULL
));
636 install_zoneinfo_file(const char *zoneinfo_file
)
639 char title
[64], prompt
[SILLY_BUFFER_SIZE
];
642 int fd1
, fd2
, copymode
;
644 if (lstat(path_localtime
, &sb
) < 0) {
645 /* Nothing there yet... */
647 } else if (S_ISLNK(sb
.st_mode
))
653 snprintf(title
, sizeof(title
), "Info");
654 if (zoneinfo_file
== NULL
)
655 snprintf(prompt
, sizeof(prompt
),
656 "Removing %s", path_localtime
);
658 snprintf(prompt
, sizeof(prompt
),
659 "Copying %s to %s", zoneinfo_file
, path_localtime
);
661 snprintf(prompt
, sizeof(prompt
),
662 "Creating symbolic link %s to %s",
663 path_localtime
, zoneinfo_file
);
665 dialog_msgbox(title
, prompt
, 8, 72, 1);
667 fprintf(stderr
, "%s\n", prompt
);
671 if (zoneinfo_file
== NULL
) {
672 if (unlink(path_localtime
) < 0 && errno
!= ENOENT
) {
673 snprintf(title
, sizeof(title
), "Error");
674 snprintf(prompt
, sizeof(prompt
),
675 "Could not delete %s: %s", path_localtime
,
678 dialog_msgbox(title
, prompt
, 8, 72, 1);
680 fprintf(stderr
, "%s\n", prompt
);
682 return (DITEM_FAILURE
| DITEM_RECREATE
);
684 if (unlink(path_db
) < 0 && errno
!= ENOENT
) {
685 snprintf(title
, sizeof(title
), "Error");
686 snprintf(prompt
, sizeof(prompt
),
687 "Could not delete %s: %s", path_db
,
690 dialog_msgbox(title
, prompt
, 8, 72, 1);
692 fprintf(stderr
, "%s\n", prompt
);
694 return (DITEM_FAILURE
| DITEM_RECREATE
);
697 snprintf(title
, sizeof(title
), "Done");
698 snprintf(prompt
, sizeof(prompt
),
699 "Removed %s", path_localtime
);
701 dialog_msgbox(title
, prompt
, 8, 72, 1);
703 fprintf(stderr
, "%s\n", prompt
);
705 return (DITEM_LEAVE_MENU
);
709 fd1
= open(zoneinfo_file
, O_RDONLY
, 0);
711 snprintf(title
, sizeof(title
), "Error");
712 snprintf(prompt
, sizeof(prompt
),
713 "Could not open %s: %s", zoneinfo_file
,
716 dialog_msgbox(title
, prompt
, 8, 72, 1);
718 fprintf(stderr
, "%s\n", prompt
);
719 return (DITEM_FAILURE
| DITEM_RECREATE
);
722 if (unlink(path_localtime
) < 0 && errno
!= ENOENT
) {
723 snprintf(prompt
, sizeof(prompt
),
724 "Could not unlink %s: %s",
725 path_localtime
, strerror(errno
));
727 snprintf(title
, sizeof(title
), "Error");
728 dialog_msgbox(title
, prompt
, 8, 72, 1);
730 fprintf(stderr
, "%s\n", prompt
);
731 return (DITEM_FAILURE
| DITEM_RECREATE
);
734 fd2
= open(path_localtime
, O_CREAT
| O_EXCL
| O_WRONLY
,
735 S_IRUSR
| S_IRGRP
| S_IROTH
);
737 snprintf(title
, sizeof(title
), "Error");
738 snprintf(prompt
, sizeof(prompt
),
739 "Could not open %s: %s",
740 path_localtime
, strerror(errno
));
742 dialog_msgbox(title
, prompt
, 8, 72, 1);
744 fprintf(stderr
, "%s\n", prompt
);
745 return (DITEM_FAILURE
| DITEM_RECREATE
);
748 while ((len
= read(fd1
, buf
, sizeof(buf
))) > 0)
749 if ((len
= write(fd2
, buf
, len
)) < 0)
753 snprintf(title
, sizeof(title
), "Error");
754 snprintf(prompt
, sizeof(prompt
),
755 "Error copying %s to %s %s", zoneinfo_file
,
756 path_localtime
, strerror(errno
));
758 dialog_msgbox(title
, prompt
, 8, 72, 1);
760 fprintf(stderr
, "%s\n", prompt
);
761 /* Better to leave none than a corrupt one. */
762 unlink(path_localtime
);
763 return (DITEM_FAILURE
| DITEM_RECREATE
);
768 if (access(zoneinfo_file
, R_OK
) != 0) {
769 snprintf(title
, sizeof(title
), "Error");
770 snprintf(prompt
, sizeof(prompt
),
771 "Cannot access %s: %s", zoneinfo_file
,
774 dialog_msgbox(title
, prompt
, 8, 72, 1);
776 fprintf(stderr
, "%s\n", prompt
);
777 return (DITEM_FAILURE
| DITEM_RECREATE
);
779 if (unlink(path_localtime
) < 0 && errno
!= ENOENT
) {
780 snprintf(prompt
, sizeof(prompt
),
781 "Could not unlink %s: %s",
782 path_localtime
, strerror(errno
));
784 snprintf(title
, sizeof(title
), "Error");
785 dialog_msgbox(title
, prompt
, 8, 72, 1);
787 fprintf(stderr
, "%s\n", prompt
);
788 return (DITEM_FAILURE
| DITEM_RECREATE
);
790 if (symlink(zoneinfo_file
, path_localtime
) < 0) {
791 snprintf(title
, sizeof(title
), "Error");
792 snprintf(prompt
, sizeof(prompt
),
793 "Cannot create symbolic link %s to %s: %s",
794 path_localtime
, zoneinfo_file
,
797 dialog_msgbox(title
, prompt
, 8, 72, 1);
799 fprintf(stderr
, "%s\n", prompt
);
800 return (DITEM_FAILURE
| DITEM_RECREATE
);
805 snprintf(title
, sizeof(title
), "Done");
807 snprintf(prompt
, sizeof(prompt
),
808 "Copied timezone file from %s to %s",
809 zoneinfo_file
, path_localtime
);
811 snprintf(prompt
, sizeof(prompt
),
812 "Created symbolic link from %s to %s",
813 zoneinfo_file
, path_localtime
);
815 dialog_msgbox(title
, prompt
, 8, 72, 1);
817 fprintf(stderr
, "%s\n", prompt
);
821 return (DITEM_LEAVE_MENU
);
825 install_zoneinfo(const char *zoneinfo
)
829 char path_zoneinfo_file
[MAXPATHLEN
];
831 sprintf(path_zoneinfo_file
, "%s/%s", path_zoneinfo
, zoneinfo
);
832 rv
= install_zoneinfo_file(path_zoneinfo_file
);
834 /* Save knowledge for later */
835 if (reallydoit
&& (rv
& DITEM_FAILURE
) == 0) {
836 if ((f
= fopen(path_db
, "w")) != NULL
) {
837 fprintf(f
, "%s\n", zoneinfo
);
846 confirm_zone(const char *filename
)
848 char title
[64], prompt
[64];
853 setenv("TZ", filename
== NULL
? "" : filename
, 1);
857 snprintf(title
, sizeof(title
), "Confirmation");
858 snprintf(prompt
, sizeof(prompt
),
859 "Does the abbreviation `%s' look reasonable?", tm
->tm_zone
);
860 rv
= !dialog_yesno(title
, prompt
, 5, 72);
865 set_zone_multi(dialogMenuItem
*dmi
)
867 struct zone
*zp
= dmi
->data
;
870 if (!confirm_zone(zp
->filename
))
871 return (DITEM_FAILURE
| DITEM_RECREATE
);
873 rv
= install_zoneinfo(zp
->filename
);
878 set_zone_whole_country(dialogMenuItem
*dmi
)
880 struct country
*cp
= dmi
->data
;
883 if (!confirm_zone(cp
->filename
))
884 return (DITEM_FAILURE
| DITEM_RECREATE
);
886 rv
= install_zoneinfo(cp
->filename
);
894 fprintf(stderr
, "usage: tzsetup [-nrs] [-C chroot_directory]"
895 " [zoneinfo_file | zoneinfo_name]\n");
900 main(int argc
, char **argv
)
902 char title
[64], prompt
[128];
903 int c
, fd
, rv
, skiputc
;
906 while ((c
= getopt(argc
, argv
, "C:nrs")) != -1) {
926 if (argc
- optind
> 1)
929 if (chrootenv
== NULL
) {
930 strcpy(path_zonetab
, _PATH_ZONETAB
);
931 strcpy(path_iso3166
, _PATH_ISO3166
);
932 strcpy(path_zoneinfo
, _PATH_ZONEINFO
);
933 strcpy(path_localtime
, _PATH_LOCALTIME
);
934 strcpy(path_db
, _PATH_DB
);
935 strcpy(path_wall_cmos_clock
, _PATH_WALL_CMOS_CLOCK
);
937 sprintf(path_zonetab
, "%s/%s", chrootenv
, _PATH_ZONETAB
);
938 sprintf(path_iso3166
, "%s/%s", chrootenv
, _PATH_ISO3166
);
939 sprintf(path_zoneinfo
, "%s/%s", chrootenv
, _PATH_ZONEINFO
);
940 sprintf(path_localtime
, "%s/%s", chrootenv
, _PATH_LOCALTIME
);
941 sprintf(path_db
, "%s/%s", chrootenv
, _PATH_DB
);
942 sprintf(path_wall_cmos_clock
, "%s/%s", chrootenv
,
943 _PATH_WALL_CMOS_CLOCK
);
947 /* Override the user-supplied umask. */
948 umask(S_IWGRP
| S_IWOTH
);
950 if (reinstall
== 1) {
952 char zoneinfo
[MAXPATHLEN
];
954 if ((f
= fopen(path_db
, "r")) != NULL
) {
955 if (fgets(zoneinfo
, sizeof(zoneinfo
), f
) != NULL
) {
956 zoneinfo
[sizeof(zoneinfo
) - 1] = 0;
957 if (strlen(zoneinfo
) > 0) {
958 zoneinfo
[strlen(zoneinfo
) - 1] = 0;
959 rv
= install_zoneinfo(zoneinfo
);
960 exit(rv
& ~DITEM_LEAVE_MENU
);
962 errx(1, "Error reading %s.\n", path_db
);
966 "Unable to determine earlier installed zoneinfo "
967 "name. Check %s", path_db
);
969 errx(1, "Cannot open %s for reading. Does it exist?", path_db
);
973 * If the arguments on the command-line do not specify a file,
974 * then interpret it as a zoneinfo name
976 if (optind
== argc
- 1) {
979 if (stat(argv
[optind
], &sb
) != 0) {
981 rv
= install_zoneinfo(argv
[optind
]);
982 exit(rv
& ~DITEM_LEAVE_MENU
);
987 read_iso3166_table();
992 init_dialog(stdin
, stdout
);
994 DIALOG_VARS save_vars
;
997 snprintf(title
, sizeof(title
),
998 "Select local or UTC (Greenwich Mean Time) clock");
999 snprintf(prompt
, sizeof(prompt
),
1000 "Is this machine's CMOS clock set to UTC? "
1001 "If it is set to local time,\n"
1002 "or you don't know, please choose NO here!");
1003 dlg_save_vars(&save_vars
);
1004 yesno
= dialog_yesno(title
, prompt
, 7, 73);
1005 dlg_restore_vars(&save_vars
);
1008 unlink(path_wall_cmos_clock
);
1011 fd
= open(path_wall_cmos_clock
,
1012 O_WRONLY
| O_CREAT
| O_TRUNC
,
1013 S_IRUSR
| S_IRGRP
| S_IROTH
);
1017 path_wall_cmos_clock
);
1024 if (optind
== argc
- 1) {
1025 snprintf(title
, sizeof(title
), "Default timezone provided");
1026 snprintf(prompt
, sizeof(prompt
),
1027 "\nUse the default `%s' zone?", argv
[optind
]);
1028 if (!dialog_yesno(title
, prompt
, 7, 72)) {
1029 rv
= install_zoneinfo_file(argv
[optind
]);
1032 exit(rv
& ~DITEM_LEAVE_MENU
);
1036 snprintf(title
, sizeof(title
), "Time Zone Selector");
1037 snprintf(prompt
, sizeof(prompt
), "Select a region");
1038 xdialog_menu(title
, prompt
, -1, -1, NCONTINENTS
, NCONTINENTS
,