timezone revision 260678
1#!/bin/sh
2#-
3# Copyright (c) 2011-2013 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD: stable/10/usr.sbin/bsdconfig/timezone/timezone 260678 2014-01-15 07:49:17Z dteske $
28#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_dprintf "%s: loading includes..." "$0"
34f_include $BSDCFG_SHARE/dialog.subr
35f_include $BSDCFG_SHARE/mustberoot.subr
36f_include $BSDCFG_SHARE/strings.subr
37f_include $BSDCFG_SHARE/timezone/continents.subr
38f_include $BSDCFG_SHARE/timezone/countries.subr
39f_include $BSDCFG_SHARE/timezone/iso3166.subr
40f_include $BSDCFG_SHARE/timezone/menus.subr
41f_include $BSDCFG_SHARE/timezone/zones.subr
42
43BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="090.timezone"
44f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
45
46f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
47	pgm="${ipgm:-$pgm}"
48
49############################################################ CONFIGURATION
50
51#
52# Standard pathnames
53#
54_PATH_DB="/var/db/zoneinfo"
55_PATH_WALL_CMOS_CLOCK="/etc/wall_cmos_clock"
56
57############################################################ GLOBALS
58
59#
60# Options
61#
62REALLYDOIT=1
63REINSTALL=
64USEDIALOG=1
65SKIPUTC=
66VERBOSE=
67TZ_OR_FAIL=
68CHROOTENV=
69
70#
71# Dummy vars (populated dynamically)
72#
73COUNTRIES= # list of 2-character country codes created by f_read_iso3166_table
74
75############################################################ FUNCTIONS
76
77# dialog_menu_main
78#
79# Display the dialog(1)-based application main menu.
80#
81dialog_menu_main()
82{
83	local title="$DIALOG_TITLE"
84	local btitle="$DIALOG_BACKTITLE"
85	local prompt="$msg_select_region"
86	local defaultitem= # Calculated below
87	local hline=
88
89	local height width rows
90	eval f_dialog_menu_size height width rows \
91	                        \"\$title\"  \
92	                        \"\$btitle\" \
93	                        \"\$prompt\" \
94	                        \"\$hline\"  \
95	                        $continent_menu_list
96
97	# Obtain default-item from previously stored selection
98	f_dialog_default_fetch defaultitem
99
100	local menu_choice
101	menu_choice=$( eval $DIALOG \
102		--title \"\$title\"              \
103		--backtitle \"\$btitle\"         \
104		--hline \"\$hline\"              \
105		--ok-label \"\$msg_ok\"          \
106		--cancel-label \"\$msg_cancel\"  \
107		--default-item \"\$defaultitem\" \
108		--menu \"\$prompt\"              \
109		$height $width $rows             \
110		$continent_menu_list             \
111		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
112	)
113	local retval=$?
114	f_dialog_data_sanitize menu_choice
115	f_dialog_menutag_store "$menu_choice"
116	f_dialog_default_store "$menu_choice"
117	return $retval
118}
119
120############################################################ MAIN
121
122# Incorporate rc-file if it exists
123[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
124
125#
126# Process command-line arguments
127#
128while getopts C:ehnrsv$GETOPTS_STDARGS flag; do
129	case "$flag" in
130	C) CHROOTENV="$OPTARG" ;;
131	e) TZ_OR_FAIL=1 ;;
132	n) REALLYDOIT= ;;
133	r) REINSTALL=1
134	   USEDIALOG= ;;
135	s) SKIPUTC=1 ;;
136	v) VERBOSE=1 ;;
137	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
138	esac
139done
140shift $(( $OPTIND - 1 ))
141
142#
143# Initialize
144#
145f_dialog_title "$msg_time_zone"
146f_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
147f_mustberoot_init
148
149#
150# Process `-C chroot_directory' command-line argument
151#
152if [ "$CHROOTENV" ]; then
153	_PATH_ZONETAB="$CHROOTENV$_PATH_ZONETAB"
154	_PATH_ISO3166="$CHROOTENV$_PATH_ISO3166"
155	_PATH_ZONEINFO="$CHROOTENV$_PATH_ZONEINFO"
156	_PATH_LOCALTIME="$CHROOTENV$_PATH_LOCALTIME"
157	_PATH_DB="$CHROOTENV$_PATH_DB"
158	_PATH_WALL_CMOS_CLOCK="$CHROOTENV$_PATH_WALL_CMOS_CLOCK"
159fi
160
161#
162# Process `-r' command-line option
163#
164if [ "$REINSTALL" ]; then
165	[ -f "$_PATH_DB" -a -r "$_PATH_DB" ] ||
166		f_die 1 "$msg_cannot_open_for_reading" "$_PATH_DB"
167	f_eval_catch -dk zoneinfo "$0" cat 'cat "%s"' "$_PATH_DB" ||
168		f_die 1 "$msg_error_reading" "$_PATH_DB"
169	[ "$zoneinfo" ] ||
170		f_die 1 "$msg_unable_to_determine_name_from_db" "$_PATH_DB"
171	f_install_zoneinfo "$zoneinfo"
172	exit $?
173fi
174
175#
176# If the arguments on the command-line do not specify a file,
177# then interpret it as a zoneinfo name
178#
179if [ $# -ge 1 ]; then
180	zoneinfo="$1"
181
182	if [ ! -f "$zoneinfo" ]; then
183		USEDIALOG=
184		f_install_zoneinfo "$zoneinfo"
185		exit $?
186	fi
187
188	# FALLTHROUGH
189fi
190
191#
192# Process the UTC option
193#
194if [ "$_PATH_WALL_CMOS_CLOCK" -a ! "$SKIPUTC" ]; then
195	f_dialog_title "$msg_select_local_or_utc"
196	title="$DIALOG_TITLE"
197	btitle="$DIALOG_BACKTITLE"
198	f_dialog_title_restore
199	msg="$msg_is_machine_clock_utc"
200
201	if [ "$USE_XDIALOG" ]; then
202		defaultno="default-no"
203		height=10 width=77
204	else
205		defaultno="defaultno"
206		height=7 width=73
207	fi
208
209	if [ "$USE_XDIALOG" ]; then
210		$DIALOG \
211			--title "$title"         \
212			--backtitle "$btitle"    \
213			--$defaultno             \
214			--ok-label "$msg_yes"    \
215			--cancel-label "$msg_no" \
216			--yesno "$msg" $height $width
217		result=$?
218	else
219		$DIALOG \
220			--title "$title"       \
221			--backtitle "$btitle"  \
222			--$defaultno           \
223			--yes-label "$msg_yes" \
224			--no-label "$msg_no"   \
225			--yesno "$msg" $height $width
226		result=$?
227	fi
228
229	if [ $result -eq $DIALOG_OK ]; then
230		# User chose YES
231		[ "$REALLYDOIT" ] &&
232			f_quietly rm -f "$_PATH_WALL_CMOS_CLOCK"
233	else
234		# User chose NO, pressed ESC (or Ctrl-C), or closed box
235		[ "$REALLYDOIT" ] &&
236			( umask 222 && :> "$_PATH_WALL_CMOS_CLOCK" )
237	fi
238fi
239
240#
241# Process optional default zone argument
242#
243if [ $# -ge 1 ]; then
244	default="$1"
245
246	f_dialog_title "$msg_default_zone_provided"
247	f_sprintf msg "\n$msg_use_default_zone" "$default"
248	hline=
249	f_dialog_yesno "$msg" "$hline"
250	result=$?
251	f_dialog_title_restore
252
253	if [ $result -eq $DIALOG_OK ]; then
254		# User chose YES
255		f_install_zoneinfo_file "$default"
256		result=$?
257		[ ! "$USE_XDIALOG" ] && f_dialog_clear
258		exit $result
259	fi
260
261	[ ! "$USE_XDIALOG" ] && f_dialog_clear
262fi
263
264#
265# Override the user-supplied umask
266#
267umask 022
268
269#
270# Read databases and perform initialization
271#
272f_read_iso3166_table # creates $COUNTRIES and $country_*_name
273f_read_zones         # creates $country_*_{descr,cont,filename}
274f_sort_countries     # sorts the countries listed for each continent
275f_make_menus         # creates $continent_menu_list and $continent_*_menu_list
276
277#
278# Launch application main menu
279#
280defaultctry=""
281defaultzone=""
282NEED_CONTINENT=1
283NEED_COUNTRY=1
284while :; do
285	if [ "$NEED_CONTINENT" ]; then
286		dialog_menu_main # prompt the user to select a continent/ocean
287		retval=$?
288		f_dialog_menutag_fetch mtag
289
290		if [ $retval -ne $DIALOG_OK ]; then
291			[ "$TZ_OR_FAIL" ] && f_die
292			exit $SUCCESS
293		fi
294
295		NEED_CONTINENT=
296
297		continent=$( eval f_dialog_menutag2item \"\$mtag\" \
298		                  	$continent_menu_list )
299		cont=$( f_find_continent "$continent" )
300		cont_title=$( f_continent $cont title )
301		nitems=$( f_continent $cont nitems )
302		isocean=$( f_OCEANP $cont )
303	fi
304
305	if [ "$NEED_COUNTRY" ]; then
306		if [ "$cont_title" = "$continent_utc_title" ]; then
307			if f_set_zone_utc; then
308				break
309			else
310				NEED_CONTINENT=1
311				continue
312			fi
313		fi
314
315		#
316		# Short cut -- if there's only one country, don't post a menu.
317		#
318		if [ $nitems -eq 1 ]; then
319			tag=1
320		else
321			#
322			# It's amazing how much good grammar really matters...
323			#
324			if [ ! "$isocean" ]; then
325				f_sprintf title "$msg_country_title" \
326				                "$cont_title"
327				f_dialog_title "$title"
328				title="$DIALOG_TITLE"
329				btitle="$DIALOG_BACKTITLE"
330				f_dialog_title_restore
331				prompt="$msg_select_country"
332			else
333				f_sprintf title "$msg_island_and_group_title" \
334				                "$cont_title"
335				f_dialog_title "$title"
336				title="$DIALOG_TITLE"
337				btitle="$DIALOG_BACKTITLE"
338				f_dialog_title_restore
339				prompt="$msg_select_island_or_group"
340			fi
341
342			#
343			# Calculate size of menu
344			#
345			menu_list=$( f_continent $cont menu_list )
346			eval f_dialog_menu_size height width rows \
347			                        \"\$title\"  \
348			                        \"\$btitle\" \
349			                        \"\$prompt\" \
350			                        \"\"         \
351			                        $menu_list
352
353			#
354			# Launch the country selection menu
355			#
356			tag=$( eval $DIALOG \
357				--title \"\$title\"              \
358				--backtitle \"\$btitle\"         \
359				--ok-label \"\$msg_ok\"          \
360				--cancel-label \"\$msg_cancel\"  \
361				--default-item \"\$defaultctry\" \
362				--menu \"\$prompt\"              \
363				$height $width $rows             \
364				$menu_list                       \
365				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
366			)
367			retval=$?
368			f_dialog_data_sanitize tag
369			defaultctry="$tag"
370
371			if [ $retval -ne $DIALOG_OK ]; then
372				NEED_CONTINENT=1
373				continue # back to main menu
374			fi
375		fi
376
377		# Get the country code from the user's selection 
378		tlc=$( f_continent $cont tlc_$tag )
379
380		NEED_COUNTRY=
381	fi
382
383	#
384	# If the selection has only one zone (nzones == -1),
385	# just set it.
386	#
387	nzones=$( f_country $tlc nzones )
388	if [ $nzones -lt 0 ]; then
389		real_cont=$( f_country $tlc cont )
390		real_continent=$( f_continent $real_cont name )
391		name=$( f_country $tlc name )
392		filename=$( f_country $tlc filename )
393
394		if ! f_confirm_zone "$real_continent/$filename"; then
395			[ $nitems -eq 1 ] && NEED_CONTINENT=1
396			NEED_COUNTRY=1
397			continue
398		fi
399	else
400		f_sprintf title "$msg_country_time_zones" \
401		                "$( f_country $tlc name )"
402		f_dialog_title "$title"
403		title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
404		f_dialog_title_restore
405		prompt="$msg_select_zone"
406		menu_list=$( f_country $tlc menu_list )
407		eval f_dialog_menu_size height width rows \
408			\"\$title\"  \"\$btitle\" \"\$prompt\" \"\" $menu_list
409
410		#
411		# Launch the zone selection menu
412		# NOTE: This is as deep as we go
413		#
414		n=$( eval $DIALOG \
415			--title \"\$title\"              \
416			--backtitle \"\$btitle\"         \
417			--ok-label \"\$msg_ok\"          \
418			--cancel-label \"\$msg_cancel\"  \
419			--default-item \"\$defaultzone\" \
420			--menu \"\$prompt\"              \
421			$height $width $rows             \
422			$menu_list                       \
423			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
424		)
425		retval=$?
426		f_dialog_data_sanitize n
427		defaultzone="$n"
428
429		if [ $retval -ne $DIALOG_OK ]; then
430			[ $nitems -eq 1 ] && NEED_CONTINENT=1
431			NEED_COUNTRY=1
432			continue
433		fi
434
435		real_cont=$( f_country $tlc cont_$n )
436		real_continent=$( f_continent $real_cont name )
437		name=$( f_country $tlc name )
438		filename=$( f_country $tlc filename_$n )
439
440		f_confirm_zone "$real_continent/$filename" || continue
441	fi
442
443	[ $retval -eq $DIALOG_OK ] || continue # back to main menu
444
445	if ! f_install_zoneinfo "$real_continent/$filename"; then
446		[ $nzones -lt 0 ] && NEED_COUNTRY=1
447	else
448		break
449	fi
450done
451
452################################################################################
453# END
454################################################################################
455