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 337522 2018-08-09 02:47:22Z delphij $
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>
49 #include <sys/sysctl.h>
55 #define _PATH_ZONETAB "/usr/share/zoneinfo/zone.tab"
56 #define _PATH_ISO3166 "/usr/share/misc/iso3166"
57 #define _PATH_ZONEINFO "/usr/share/zoneinfo"
58 #define _PATH_LOCALTIME "/etc/localtime"
59 #define _PATH_DB "/var/db/zoneinfo"
60 #define _PATH_WALL_CMOS_CLOCK "/etc/wall_cmos_clock"
63 #define SILLY_BUFFER_SIZE 2*PATH_MAX
65 #warning "Somebody needs to fix this to dynamically size this buffer."
66 #define SILLY_BUFFER_SIZE 2048
69 /* special return codes for `fire' actions */
70 #define DITEM_FAILURE 1
72 /* flags - returned in upper 16 bits of return status */
73 #define DITEM_LEAVE_MENU (1 << 16)
74 #define DITEM_RECREATE (1 << 18)
76 static char path_zonetab
[MAXPATHLEN
], path_iso3166
[MAXPATHLEN
],
77 path_zoneinfo
[MAXPATHLEN
], path_localtime
[MAXPATHLEN
],
78 path_db
[MAXPATHLEN
], path_wall_cmos_clock
[MAXPATHLEN
];
80 static int reallydoit
= 1;
81 static int reinstall
= 0;
82 static char *chrootenv
= NULL
;
84 static void usage(void);
85 static int install_zoneinfo(const char *zoneinfo
);
86 static int install_zoneinfo_file(const char *zoneinfo_file
);
89 /* for use in describing more exotic behaviors */
90 typedef struct dialogMenuItem
{
93 int (*fire
)(struct dialogMenuItem
*self
);
98 xdialog_count_rows(const char *p
)
102 while ((p
= strchr(p
, '\n')) != NULL
) {
109 return (rows
? rows
: 1);
113 xdialog_count_columns(const char *p
)
119 for (; (q
= strchr(p
, '\n')) != NULL
; p
= q
+ 1) {
121 max_len
= MAX(max_len
, len
);
125 max_len
= MAX(max_len
, len
);
130 xdialog_menu(const char *title
, const char *cprompt
, int height
, int width
,
131 int menu_height
, int item_no
, dialogMenuItem
*ditems
)
133 int i
, result
, choice
= 0;
134 DIALOG_LISTITEM
*listitems
;
135 DIALOG_VARS save_vars
;
137 dlg_save_vars(&save_vars
);
139 /* initialize list items */
140 listitems
= calloc(item_no
+ 1, sizeof(DIALOG_LISTITEM
));
141 if (listitems
== NULL
)
142 errx(1, "Failed to allocate memory in xdialog_menu");
143 for (i
= 0; i
< item_no
; i
++) {
144 listitems
[i
].name
= ditems
[i
].prompt
;
145 listitems
[i
].text
= ditems
[i
].title
;
148 /* calculate height */
150 height
= xdialog_count_rows(cprompt
) + menu_height
+ 4 + 2;
154 /* calculate width */
158 for (i
= 0; i
< item_no
; i
++) {
161 l
= strlen(listitems
[i
].name
);
162 for (j
= 0; j
< item_no
; j
++) {
163 int k
= strlen(listitems
[j
].text
);
164 tag_x
= MAX(tag_x
, l
+ k
+ 2);
167 width
= MAX(xdialog_count_columns(cprompt
), title
!= NULL
?
168 xdialog_count_columns(title
) : 0);
169 width
= MAX(width
, tag_x
+ 4) + 4;
171 width
= MAX(width
, 24);
176 dialog_vars
.default_item
= listitems
[choice
].name
;
177 result
= dlg_menu(title
, cprompt
, height
, width
,
178 menu_height
, item_no
, listitems
, &choice
, NULL
);
184 if (ditems
[choice
].fire
!= NULL
) {
187 status
= ditems
[choice
].fire(ditems
+ choice
);
188 if (status
& DITEM_RECREATE
) {
195 case DLG_EXIT_CANCEL
:
202 dlg_restore_vars(&save_vars
);
206 static int usedialog
= 1;
208 static int confirm_zone(const char *filename
);
209 static int continent_country_menu(dialogMenuItem
*);
210 static int set_zone_multi(dialogMenuItem
*);
211 static int set_zone_whole_country(dialogMenuItem
*);
212 static int set_zone_menu(dialogMenuItem
*);
213 static int set_zone_utc(void);
216 dialogMenuItem
*menu
;
220 static struct continent africa
, america
, antarctica
, arctic
, asia
, atlantic
;
221 static struct continent australia
, europe
, indian
, pacific
, utc
;
223 static struct continent_names
{
225 struct continent
*continent
;
226 } continent_names
[] = {
227 { "Africa", &africa
},
228 { "America", &america
},
229 { "Antarctica", &antarctica
},
230 { "Arctic", &arctic
},
232 { "Atlantic", &atlantic
},
233 { "Australia", &australia
},
234 { "Europe", &europe
},
235 { "Indian", &indian
},
236 { "Pacific", &pacific
},
240 static struct continent_items
{
243 } continent_items
[] = {
245 { "2", "America -- North and South" },
246 { "3", "Antarctica" },
247 { "4", "Arctic Ocean" },
249 { "6", "Atlantic Ocean" },
250 { "7", "Australia" },
252 { "9", "Indian Ocean" },
253 { "0", "Pacific Ocean" },
257 #define NCONTINENTS \
258 (int)((sizeof(continent_items)) / (sizeof(continent_items[0])))
259 static dialogMenuItem continents
[NCONTINENTS
];
261 #define OCEANP(x) ((x) == 3 || (x) == 5 || (x) == 8 || (x) == 9)
264 continent_country_menu(dialogMenuItem
*continent
)
266 char title
[64], prompt
[64];
267 struct continent
*contp
= continent
->data
;
268 int isocean
= OCEANP(continent
- continents
);
272 if (strcmp(continent
->title
, "UTC") == 0)
273 return (set_zone_utc());
275 /* Short cut -- if there's only one country, don't post a menu. */
276 if (contp
->nitems
== 1)
277 return (contp
->menu
[0].fire(&contp
->menu
[0]));
279 /* It's amazing how much good grammar really matters... */
281 snprintf(title
, sizeof(title
), "Countries in %s",
283 snprintf(prompt
, sizeof(prompt
), "Select a country or region");
285 snprintf(title
, sizeof(title
), "Islands and groups in the %s",
287 snprintf(prompt
, sizeof(prompt
), "Select an island or group");
290 menulen
= contp
->nitems
< 16 ? contp
->nitems
: 16;
291 rv
= xdialog_menu(title
, prompt
, -1, -1, menulen
, contp
->nitems
,
294 return (DITEM_LEAVE_MENU
);
295 return (DITEM_RECREATE
);
298 static struct continent
*
299 find_continent(const char *name
)
303 for (i
= 0; i
< NCONTINENTS
; i
++)
304 if (strcmp(name
, continent_names
[i
].name
) == 0)
305 return (continent_names
[i
].continent
);
313 char *filename
; /* use iff nzones < 0 */
314 struct continent
*continent
; /* use iff nzones < 0 */
315 TAILQ_HEAD(, zone
) zones
; /* use iff nzones > 0 */
316 dialogMenuItem
*submenu
; /* use iff nzones > 0 */
320 TAILQ_ENTRY(zone
) link
;
323 struct continent
*continent
;
327 * This is the easiest organization... we use ISO 3166 country codes,
328 * of the two-letter variety, so we just size this array to suit.
329 * Beats worrying about dynamic allocation.
331 #define NCOUNTRIES (26 * 26)
332 static struct country countries
[NCOUNTRIES
];
334 #define CODE2INT(s) ((s[0] - 'A') * 26 + (s[1] - 'A'))
337 * Read the ISO 3166 country code database in _PATH_ISO3166
338 * (/usr/share/misc/iso3166). On error, exit via err(3).
341 read_iso3166_table(void)
349 fp
= fopen(path_iso3166
, "r");
351 err(1, "%s", path_iso3166
);
354 while ((s
= fgetln(fp
, &len
)) != NULL
) {
356 if (s
[len
- 1] != '\n')
357 errx(1, "%s:%d: invalid format", path_iso3166
, lineno
);
359 if (s
[0] == '#' || strspn(s
, " \t") == len
- 1)
362 /* Isolate the two-letter code. */
363 t
= strsep(&s
, "\t");
364 if (t
== NULL
|| strlen(t
) != 2)
365 errx(1, "%s:%d: invalid format", path_iso3166
, lineno
);
366 if (t
[0] < 'A' || t
[0] > 'Z' || t
[1] < 'A' || t
[1] > 'Z')
367 errx(1, "%s:%d: invalid code `%s'", path_iso3166
,
372 cp
= &countries
[CODE2INT(t
)];
374 errx(1, "%s:%d: country code `%s' multiply defined: %s",
375 path_iso3166
, lineno
, t
, cp
->name
);
376 cp
->name
= strdup(name
);
377 if (cp
->name
== NULL
)
378 errx(1, "malloc failed");
381 errx(1, "malloc failed");
388 add_zone_to_country(int lineno
, const char *tlc
, const char *descr
,
389 const char *file
, struct continent
*cont
)
394 if (tlc
[0] < 'A' || tlc
[0] > 'Z' || tlc
[1] < 'A' || tlc
[1] > 'Z')
395 errx(1, "%s:%d: country code `%s' invalid", path_zonetab
,
398 cp
= &countries
[CODE2INT(tlc
)];
400 errx(1, "%s:%d: country code `%s' unknown", path_zonetab
,
405 errx(1, "%s:%d: conflicting zone definition",
406 path_zonetab
, lineno
);
408 zp
= malloc(sizeof(*zp
));
410 errx(1, "malloc(%zu)", sizeof(*zp
));
413 TAILQ_INIT(&cp
->zones
);
415 zp
->descr
= strdup(descr
);
416 if (zp
->descr
== NULL
)
417 errx(1, "malloc failed");
418 zp
->filename
= strdup(file
);
419 if (zp
->filename
== NULL
)
420 errx(1, "malloc failed");
421 zp
->continent
= cont
;
422 TAILQ_INSERT_TAIL(&cp
->zones
, zp
, link
);
426 errx(1, "%s:%d: zone must have description",
427 path_zonetab
, lineno
);
429 errx(1, "%s:%d: zone multiply defined",
430 path_zonetab
, lineno
);
432 cp
->filename
= strdup(file
);
433 if (cp
->filename
== NULL
)
434 errx(1, "malloc failed");
435 cp
->continent
= cont
;
440 * This comparison function intentionally sorts all of the null-named
441 * ``countries''---i.e., the codes that don't correspond to a real
442 * country---to the end. Everything else is lexical by country name.
445 compare_countries(const void *xa
, const void *xb
)
447 const struct country
*a
= xa
, *b
= xb
;
449 if (a
->name
== 0 && b
->name
== 0)
451 if (a
->name
== 0 && b
->name
!= 0)
456 return (strcmp(a
->name
, b
->name
));
460 * This must be done AFTER all zone descriptions are read, since it breaks
467 qsort(countries
, NCOUNTRIES
, sizeof(countries
[0]), compare_countries
);
475 struct continent
*cont
;
477 char *line
, *tlc
, *file
, *descr
, *p
;
480 fp
= fopen(path_zonetab
, "r");
482 err(1, "%s", path_zonetab
);
485 while ((line
= fgetln(fp
, &len
)) != NULL
) {
487 if (line
[len
- 1] != '\n')
488 errx(1, "%s:%d: invalid format", path_zonetab
, lineno
);
489 line
[len
- 1] = '\0';
493 tlc
= strsep(&line
, "\t");
494 if (strlen(tlc
) != 2)
495 errx(1, "%s:%d: invalid country code `%s'",
496 path_zonetab
, lineno
, tlc
);
497 /* coord = */ strsep(&line
, "\t"); /* Unused */
498 file
= strsep(&line
, "\t");
499 /* get continent portion from continent/country */
500 p
= strchr(file
, '/');
502 errx(1, "%s:%d: invalid zone name `%s'", path_zonetab
,
504 contlen
= p
- file
+ 1; /* trailing nul */
505 if (contlen
> sizeof(contbuf
))
506 errx(1, "%s:%d: continent name in zone name `%s' too long",
507 path_zonetab
, lineno
, file
);
508 strlcpy(contbuf
, file
, contlen
);
509 cont
= find_continent(contbuf
);
511 errx(1, "%s:%d: invalid region `%s'", path_zonetab
,
514 descr
= (line
!= NULL
&& *line
!= '\0') ? line
: NULL
;
516 add_zone_to_country(lineno
, tlc
, descr
, file
, cont
);
525 struct zone
*zp
, *zp2
;
526 struct continent
*cont
;
531 * First, count up all the countries in each continent/ocean.
532 * Be careful to count those countries which have multiple zones
533 * only once for each. NB: some countries are in multiple
536 for (cp
= countries
; cp
->name
; cp
++) {
539 if (cp
->nzones
< 0) {
540 cp
->continent
->nitems
++;
542 TAILQ_FOREACH(zp
, &cp
->zones
, link
) {
543 cont
= zp
->continent
;
544 for (zp2
= TAILQ_FIRST(&cp
->zones
);
545 zp2
->continent
!= cont
;
546 zp2
= TAILQ_NEXT(zp2
, link
))
549 zp
->continent
->nitems
++;
555 * Now allocate memory for the country menus and initialize
556 * continent menus. We set nitems back to zero so that we can
557 * use it for counting again when we actually build the menus.
559 memset(continents
, 0, sizeof(continents
));
560 for (i
= 0; i
< NCONTINENTS
; i
++) {
561 continent_names
[i
].continent
->menu
=
562 malloc(sizeof(dialogMenuItem
) *
563 continent_names
[i
].continent
->nitems
);
564 if (continent_names
[i
].continent
->menu
== NULL
)
565 errx(1, "malloc for continent menu");
566 continent_names
[i
].continent
->nitems
= 0;
567 continents
[i
].prompt
= continent_items
[i
].prompt
;
568 continents
[i
].title
= continent_items
[i
].title
;
569 continents
[i
].fire
= continent_country_menu
;
570 continents
[i
].data
= continent_names
[i
].continent
;
574 * Now that memory is allocated, create the menu items for
575 * each continent. For multiple-zone countries, also create
576 * the country's zone submenu.
578 for (cp
= countries
; cp
->name
; cp
++) {
581 if (cp
->nzones
< 0) {
582 dmi
= &cp
->continent
->menu
[cp
->continent
->nitems
];
583 memset(dmi
, 0, sizeof(*dmi
));
584 asprintf(&dmi
->prompt
, "%d", ++cp
->continent
->nitems
);
585 dmi
->title
= cp
->name
;
586 dmi
->fire
= set_zone_whole_country
;
589 cp
->submenu
= malloc(cp
->nzones
* sizeof(*dmi
));
590 if (cp
->submenu
== 0)
591 errx(1, "malloc for submenu");
593 TAILQ_FOREACH(zp
, &cp
->zones
, link
) {
594 cont
= zp
->continent
;
595 dmi
= &cp
->submenu
[cp
->nzones
];
596 memset(dmi
, 0, sizeof(*dmi
));
597 asprintf(&dmi
->prompt
, "%d", ++cp
->nzones
);
598 dmi
->title
= zp
->descr
;
599 dmi
->fire
= set_zone_multi
;
602 for (zp2
= TAILQ_FIRST(&cp
->zones
);
603 zp2
->continent
!= cont
;
604 zp2
= TAILQ_NEXT(zp2
, link
))
609 dmi
= &cont
->menu
[cont
->nitems
];
610 memset(dmi
, 0, sizeof(*dmi
));
611 asprintf(&dmi
->prompt
, "%d", ++cont
->nitems
);
612 dmi
->title
= cp
->name
;
613 dmi
->fire
= set_zone_menu
;
621 set_zone_menu(dialogMenuItem
*dmi
)
623 char title
[64], prompt
[64];
624 struct country
*cp
= dmi
->data
;
628 snprintf(title
, sizeof(title
), "%s Time Zones", cp
->name
);
629 snprintf(prompt
, sizeof(prompt
),
630 "Select a zone which observes the same time as your locality.");
631 menulen
= cp
->nzones
< 16 ? cp
->nzones
: 16;
632 rv
= xdialog_menu(title
, prompt
, -1, -1, menulen
, cp
->nzones
,
635 return (DITEM_RECREATE
);
636 return (DITEM_LEAVE_MENU
);
642 if (!confirm_zone("UTC"))
643 return (DITEM_FAILURE
| DITEM_RECREATE
);
645 return (install_zoneinfo("UTC"));
649 confirm_zone(const char *filename
)
651 char title
[64], prompt
[64];
656 setenv("TZ", filename
, 1);
660 snprintf(title
, sizeof(title
), "Confirmation");
661 snprintf(prompt
, sizeof(prompt
),
662 "Does the abbreviation `%s' look reasonable?", tm
->tm_zone
);
663 rv
= !dialog_yesno(title
, prompt
, 5, 72);
668 set_zone_multi(dialogMenuItem
*dmi
)
670 struct zone
*zp
= dmi
->data
;
673 if (!confirm_zone(zp
->filename
))
674 return (DITEM_FAILURE
| DITEM_RECREATE
);
676 rv
= install_zoneinfo(zp
->filename
);
681 set_zone_whole_country(dialogMenuItem
*dmi
)
683 struct country
*cp
= dmi
->data
;
686 if (!confirm_zone(cp
->filename
))
687 return (DITEM_FAILURE
| DITEM_RECREATE
);
689 rv
= install_zoneinfo(cp
->filename
);
696 install_zoneinfo_file(const char *zoneinfo_file
)
699 char title
[64], prompt
[SILLY_BUFFER_SIZE
];
702 int fd1
, fd2
, copymode
;
704 if (lstat(path_localtime
, &sb
) < 0) {
705 /* Nothing there yet... */
707 } else if (S_ISLNK(sb
.st_mode
))
713 snprintf(title
, sizeof(title
), "Info");
715 snprintf(prompt
, sizeof(prompt
),
716 "Copying %s to %s", zoneinfo_file
, path_localtime
);
718 snprintf(prompt
, sizeof(prompt
),
719 "Creating symbolic link %s to %s",
720 path_localtime
, zoneinfo_file
);
723 dialog_msgbox(title
, prompt
, 8, 72, 1);
726 fprintf(stderr
, "%s\n", prompt
);
731 fd1
= open(zoneinfo_file
, O_RDONLY
, 0);
733 snprintf(title
, sizeof(title
), "Error");
734 snprintf(prompt
, sizeof(prompt
),
735 "Could not open %s: %s", zoneinfo_file
,
739 dialog_msgbox(title
, prompt
, 8, 72, 1);
742 fprintf(stderr
, "%s\n", prompt
);
743 return (DITEM_FAILURE
| DITEM_RECREATE
);
746 if (unlink(path_localtime
) < 0 && errno
!= ENOENT
) {
747 snprintf(prompt
, sizeof(prompt
),
748 "Could not delete %s: %s",
749 path_localtime
, strerror(errno
));
752 snprintf(title
, sizeof(title
), "Error");
753 dialog_msgbox(title
, prompt
, 8, 72, 1);
756 fprintf(stderr
, "%s\n", prompt
);
757 return (DITEM_FAILURE
| DITEM_RECREATE
);
760 fd2
= open(path_localtime
, O_CREAT
| O_EXCL
| O_WRONLY
,
761 S_IRUSR
| S_IRGRP
| S_IROTH
);
763 snprintf(title
, sizeof(title
), "Error");
764 snprintf(prompt
, sizeof(prompt
),
765 "Could not open %s: %s",
766 path_localtime
, strerror(errno
));
769 dialog_msgbox(title
, prompt
, 8, 72, 1);
772 fprintf(stderr
, "%s\n", prompt
);
773 return (DITEM_FAILURE
| DITEM_RECREATE
);
776 while ((len
= read(fd1
, buf
, sizeof(buf
))) > 0)
777 if ((len
= write(fd2
, buf
, len
)) < 0)
781 snprintf(title
, sizeof(title
), "Error");
782 snprintf(prompt
, sizeof(prompt
),
783 "Error copying %s to %s %s", zoneinfo_file
,
784 path_localtime
, strerror(errno
));
787 dialog_msgbox(title
, prompt
, 8, 72, 1);
790 fprintf(stderr
, "%s\n", prompt
);
791 /* Better to leave none than a corrupt one. */
792 unlink(path_localtime
);
793 return (DITEM_FAILURE
| DITEM_RECREATE
);
798 if (access(zoneinfo_file
, R_OK
) != 0) {
799 snprintf(title
, sizeof(title
), "Error");
800 snprintf(prompt
, sizeof(prompt
),
801 "Cannot access %s: %s", zoneinfo_file
,
805 dialog_msgbox(title
, prompt
, 8, 72, 1);
808 fprintf(stderr
, "%s\n", prompt
);
809 return (DITEM_FAILURE
| DITEM_RECREATE
);
811 if (unlink(path_localtime
) < 0 && errno
!= ENOENT
) {
812 snprintf(prompt
, sizeof(prompt
),
813 "Could not delete %s: %s",
814 path_localtime
, strerror(errno
));
817 snprintf(title
, sizeof(title
), "Error");
818 dialog_msgbox(title
, prompt
, 8, 72, 1);
821 fprintf(stderr
, "%s\n", prompt
);
822 return (DITEM_FAILURE
| DITEM_RECREATE
);
824 if (symlink(zoneinfo_file
, path_localtime
) < 0) {
825 snprintf(title
, sizeof(title
), "Error");
826 snprintf(prompt
, sizeof(prompt
),
827 "Cannot create symbolic link %s to %s: %s",
828 path_localtime
, zoneinfo_file
,
832 dialog_msgbox(title
, prompt
, 8, 72, 1);
835 fprintf(stderr
, "%s\n", prompt
);
836 return (DITEM_FAILURE
| DITEM_RECREATE
);
841 snprintf(title
, sizeof(title
), "Done");
843 snprintf(prompt
, sizeof(prompt
),
844 "Copied timezone file from %s to %s",
845 zoneinfo_file
, path_localtime
);
847 snprintf(prompt
, sizeof(prompt
),
848 "Created symbolic link from %s to %s",
849 zoneinfo_file
, path_localtime
);
852 dialog_msgbox(title
, prompt
, 8, 72, 1);
855 fprintf(stderr
, "%s\n", prompt
);
859 return (DITEM_LEAVE_MENU
);
863 install_zoneinfo(const char *zoneinfo
)
867 char path_zoneinfo_file
[MAXPATHLEN
+ 2];
869 if ((size_t)snprintf(path_zoneinfo_file
, sizeof(path_zoneinfo_file
),
870 "%s/%s", path_zoneinfo
, zoneinfo
) >= sizeof(path_zoneinfo_file
))
871 errx(1, "%s/%s name too long", path_zoneinfo
, zoneinfo
);
872 rv
= install_zoneinfo_file(path_zoneinfo_file
);
874 /* Save knowledge for later */
875 if (reallydoit
&& (rv
& DITEM_FAILURE
) == 0) {
876 if ((f
= fopen(path_db
, "w")) != NULL
) {
877 fprintf(f
, "%s\n", zoneinfo
);
889 fprintf(stderr
, "usage: tzsetup [-nrs] [-C chroot_directory]"
890 " [zoneinfo_file | zoneinfo_name]\n");
895 main(int argc
, char **argv
)
898 char title
[64], prompt
[128];
903 char vmm_guest
[16] = "";
904 size_t len
= sizeof(vmm_guest
);
909 /* Default skiputc to 1 for VM guests */
910 if (sysctlbyname("kern.vmm_guest", vmm_guest
, &len
, NULL
, 0) == 0 &&
911 strcmp(vmm_guest
, "none") != 0)
915 while ((c
= getopt(argc
, argv
, "C:nrs")) != -1) {
939 if (argc
- optind
> 1)
942 if (chrootenv
== NULL
) {
943 strcpy(path_zonetab
, _PATH_ZONETAB
);
944 strcpy(path_iso3166
, _PATH_ISO3166
);
945 strcpy(path_zoneinfo
, _PATH_ZONEINFO
);
946 strcpy(path_localtime
, _PATH_LOCALTIME
);
947 strcpy(path_db
, _PATH_DB
);
948 strcpy(path_wall_cmos_clock
, _PATH_WALL_CMOS_CLOCK
);
950 sprintf(path_zonetab
, "%s/%s", chrootenv
, _PATH_ZONETAB
);
951 sprintf(path_iso3166
, "%s/%s", chrootenv
, _PATH_ISO3166
);
952 sprintf(path_zoneinfo
, "%s/%s", chrootenv
, _PATH_ZONEINFO
);
953 sprintf(path_localtime
, "%s/%s", chrootenv
, _PATH_LOCALTIME
);
954 sprintf(path_db
, "%s/%s", chrootenv
, _PATH_DB
);
955 sprintf(path_wall_cmos_clock
, "%s/%s", chrootenv
,
956 _PATH_WALL_CMOS_CLOCK
);
959 /* Override the user-supplied umask. */
960 umask(S_IWGRP
| S_IWOTH
);
962 if (reinstall
== 1) {
964 char zoneinfo
[MAXPATHLEN
];
966 if ((f
= fopen(path_db
, "r")) != NULL
) {
967 if (fgets(zoneinfo
, sizeof(zoneinfo
), f
) != NULL
) {
968 zoneinfo
[sizeof(zoneinfo
) - 1] = 0;
969 if (strlen(zoneinfo
) > 0) {
970 zoneinfo
[strlen(zoneinfo
) - 1] = 0;
971 rv
= install_zoneinfo(zoneinfo
);
972 exit(rv
& ~DITEM_LEAVE_MENU
);
974 errx(1, "Error reading %s.\n", path_db
);
978 "Unable to determine earlier installed zoneinfo "
979 "name. Check %s", path_db
);
981 errx(1, "Cannot open %s for reading. Does it exist?", path_db
);
985 * If the arguments on the command-line do not specify a file,
986 * then interpret it as a zoneinfo name
988 if (optind
== argc
- 1) {
991 if (stat(argv
[optind
], &sb
) != 0) {
995 rv
= install_zoneinfo(argv
[optind
]);
996 exit(rv
& ~DITEM_LEAVE_MENU
);
1002 read_iso3166_table();
1007 init_dialog(stdin
, stdout
);
1009 DIALOG_VARS save_vars
;
1012 snprintf(title
, sizeof(title
),
1013 "Select local or UTC (Greenwich Mean Time) clock");
1014 snprintf(prompt
, sizeof(prompt
),
1015 "Is this machine's CMOS clock set to UTC? "
1016 "If it is set to local time,\n"
1017 "or you don't know, please choose NO here!");
1018 dlg_save_vars(&save_vars
);
1019 yesno
= dialog_yesno(title
, prompt
, 7, 73);
1020 dlg_restore_vars(&save_vars
);
1023 unlink(path_wall_cmos_clock
);
1026 fd
= open(path_wall_cmos_clock
,
1027 O_WRONLY
| O_CREAT
| O_TRUNC
,
1028 S_IRUSR
| S_IRGRP
| S_IROTH
);
1032 path_wall_cmos_clock
);
1039 if (optind
== argc
- 1) {
1040 snprintf(title
, sizeof(title
), "Default timezone provided");
1041 snprintf(prompt
, sizeof(prompt
),
1042 "\nUse the default `%s' zone?", argv
[optind
]);
1043 if (!dialog_yesno(title
, prompt
, 7, 72)) {
1044 rv
= install_zoneinfo_file(argv
[optind
]);
1047 exit(rv
& ~DITEM_LEAVE_MENU
);
1051 snprintf(title
, sizeof(title
), "Time Zone Selector");
1052 snprintf(prompt
, sizeof(prompt
), "Select a region");
1053 xdialog_menu(title
, prompt
, -1, -1, NCONTINENTS
, NCONTINENTS
,