timezone revision 243112
1238438Sdteske#!/bin/sh
2238438Sdteske#-
3238438Sdteske# Copyright (c) 2011-2012 Devin Teske
4238438Sdteske# All Rights Reserved.
5238438Sdteske#
6238438Sdteske# Redistribution and use in source and binary forms, with or without
7238438Sdteske# modification, are permitted provided that the following conditions
8238438Sdteske# are met:
9238438Sdteske# 1. Redistributions of source code must retain the above copyright
10238438Sdteske#    notice, this list of conditions and the following disclaimer.
11238438Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12238438Sdteske#    notice, this list of conditions and the following disclaimer in the
13238438Sdteske#    documentation and/or other materials provided with the distribution.
14238438Sdteske#
15238438Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16238438Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17238438Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18238438Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19238438Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20238438Sdteske# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21238438Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22238438Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23238438Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24238438Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25238438Sdteske# SUCH DAMAGE.
26238438Sdteske#
27238438Sdteske# $FreeBSD: head/usr.sbin/bsdconfig/timezone/timezone 243112 2012-11-16 00:59:11Z dteske $
28238438Sdteske#
29238438Sdteske############################################################ INCLUDES
30238438Sdteske
31240684SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32240684Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33240684Sdteskef_include $BSDCFG_SHARE/dialog.subr
34240684Sdteskef_include $BSDCFG_SHARE/mustberoot.subr
35240684Sdteskef_include $BSDCFG_SHARE/strings.subr
36240684Sdteskef_include $BSDCFG_SHARE/timezone/continents.subr
37240684Sdteskef_include $BSDCFG_SHARE/timezone/countries.subr
38240684Sdteskef_include $BSDCFG_SHARE/timezone/iso3166.subr
39240684Sdteskef_include $BSDCFG_SHARE/timezone/menus.subr
40240684Sdteskef_include $BSDCFG_SHARE/timezone/zones.subr
41238438Sdteske
42240684SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="090.timezone"
43238438Sdteskef_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
44238438Sdteske
45243112Sdteskeipgm=$( f_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" )
46238438Sdteske[ $? -eq $SUCCESS -a "$ipgm" ] && pgm="$ipgm"
47238438Sdteske
48238438Sdteske############################################################ CONFIGURATION
49238438Sdteske
50238438Sdteske#
51238438Sdteske# Standard pathnames
52238438Sdteske#
53238438Sdteske_PATH_DB="/var/db/zoneinfo"
54238438Sdteske_PATH_WALL_CMOS_CLOCK="/etc/wall_cmos_clock"
55238438Sdteske
56238438Sdteske############################################################ GLOBALS
57238438Sdteske
58238438Sdteske#
59238438Sdteske# Options
60238438Sdteske#
61238438SdteskeREALLYDOIT=1
62238438SdteskeREINSTALL=
63238438SdteskeUSEDIALOG=1
64238438SdteskeSKIPUTC=
65238438SdteskeVERBOSE=
66238438SdteskeTZ_OR_FAIL=
67238438SdteskeCHROOTENV=
68238438Sdteske
69238438Sdteske#
70238438Sdteske# Dummy vars (populated dynamically)
71238438Sdteske#
72238438SdteskeCOUNTRIES= # list of 2-character country codes created by f_read_iso3166_table
73238438Sdteske
74238438Sdteske############################################################ FUNCTIONS
75238438Sdteske
76238438Sdteske# dialog_menu_main
77238438Sdteske#
78238438Sdteske# Display the dialog(1)-based application main menu.
79238438Sdteske#
80238438Sdteskedialog_menu_main()
81238438Sdteske{
82238438Sdteske	local title="$DIALOG_TITLE"
83238438Sdteske	local btitle="$DIALOG_BACKTITLE"
84238438Sdteske	local prompt="$msg_select_region"
85238438Sdteske	local size
86238438Sdteske
87238438Sdteske	size=$( eval f_dialog_menu_size \
88238438Sdteske	        	\"\$title\"  \
89238438Sdteske	        	\"\$btitle\" \
90238438Sdteske	        	\"\$prompt\" \
91238438Sdteske			\"\"         \
92238438Sdteske	        	$continent_menu_list )
93238438Sdteske
94240768Sdteske	local dialog_menu
95240768Sdteske	dialog_menu=$( eval $DIALOG \
96238438Sdteske		--title \"\$title\"             \
97238438Sdteske		--backtitle \"\$btitle\"        \
98238438Sdteske		--ok-label \"\$msg_ok\"         \
99238438Sdteske		--cancel-label \"\$msg_cancel\" \
100238438Sdteske		--menu \"\$prompt\" $size       \
101238438Sdteske		$continent_menu_list            \
102240768Sdteske		2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
103240768Sdteske	)
104240768Sdteske	local retval=$?
105240768Sdteske	setvar DIALOG_MENU_$$ "$dialog_menu"
106240768Sdteske	return $retval
107238438Sdteske}
108238438Sdteske
109238438Sdteske############################################################ MAIN
110238438Sdteske
111238438Sdteske# Incorporate rc-file if it exists
112238438Sdteske[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
113238438Sdteske
114238438Sdteske#
115238438Sdteske# Process command-line arguments
116238438Sdteske#
117238438Sdteskewhile getopts C:ehnrsSvX flag; do
118238438Sdteske	case "$flag" in
119238438Sdteske	C) CHROOTENV="$OPTARG";;
120238438Sdteske	e) TZ_OR_FAIL=1;;
121238438Sdteske	n) REALLYDOIT=;;
122238438Sdteske	r) REINSTALL=1
123238438Sdteske	   USEDIALOG=;;
124238438Sdteske	s) SKIPUTC=1;;
125238438Sdteske	v) VERBOSE=1;;
126238438Sdteske	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm";;
127238438Sdteske	esac
128238438Sdteskedone
129238438Sdteskeshift $(( $OPTIND - 1 ))
130238438Sdteske
131238438Sdteske#
132238438Sdteske# Initialize
133238438Sdteske#
134238438Sdteskef_dialog_init
135238438Sdteskef_dialog_title "$msg_time_zone"
136238438Sdteskef_dialog_backtitle "${ipgm:+bsdconfig }$pgm"
137238438Sdteskef_mustberoot_init
138238438Sdteske
139238438Sdteske#
140238438Sdteske# Process `-C chroot_directory' command-line argument
141238438Sdteske#
142238438Sdteskeif [ "$CHROOTENV" ]; then
143238438Sdteske	_PATH_ZONETAB="$CHROOTENV$_PATH_ZONETAB"
144238438Sdteske	_PATH_ISO3166="$CHROOTENV$_PATH_ISO3166"
145238438Sdteske	_PATH_ZONEINFO="$CHROOTENV$_PATH_ZONEINFO"
146238438Sdteske	_PATH_LOCALTIME="$CHROOTENV$_PATH_LOCALTIME"
147238438Sdteske	_PATH_DB="$CHROOTENV$_PATH_DB"
148238438Sdteske	_PATH_WALL_CMOS_CLOCK="$CHROOTENV$_PATH_WALL_CMOS_CLOCK"
149238438Sdteskefi
150238438Sdteske
151238438Sdteske#
152238438Sdteske# Process `-r' command-line option
153238438Sdteske#
154238438Sdteskeif [ "$REINSTALL" ]; then
155238438Sdteske	[ -f "$_PATH_DB" -a -r "$_PATH_DB" ] ||
156238438Sdteske		f_die 1 "$msg_cannot_open_for_reading" "$_PATH_DB"
157238438Sdteske	zoneinfo=$( cat "$_PATH_DB" ) ||
158238438Sdteske		f_die 1 "$msg_error_reading" "$_PATH_DB"
159238438Sdteske	[ "$zoneinfo" ] ||
160238438Sdteske		f_die 1 "$msg_unable_to_determine_name_from_db" "$_PATH_DB"
161238438Sdteske	f_install_zoneinfo "$zoneinfo"
162238438Sdteske	exit $?
163238438Sdteskefi
164238438Sdteske
165238438Sdteske#
166238438Sdteske# If the arguments on the command-line do not specify a file,
167238438Sdteske# then interpret it as a zoneinfo name
168238438Sdteske#
169238438Sdteskeif [ $# -ge 1 ]; then
170238438Sdteske	zoneinfo="$1"
171238438Sdteske
172238438Sdteske	if [ ! -f "$zoneinfo" ]; then
173238438Sdteske		USEDIALOG=
174238438Sdteske		f_install_zoneinfo "$zoneinfo"
175238438Sdteske		exit $?
176238438Sdteske	fi
177238438Sdteske
178238438Sdteske	# FALLTHROUGH
179238438Sdteskefi
180238438Sdteske
181238438Sdteske#
182238438Sdteske# Process the UTC option
183238438Sdteske#
184238438Sdteskeif [ "$_PATH_WALL_CMOS_CLOCK" -a ! "$SKIPUTC" ]; then
185238438Sdteske	f_dialog_title "$msg_select_local_or_utc"
186238438Sdteske	title="$DIALOG_TITLE"
187238438Sdteske	btitle="$DIALOG_BACKTITLE"
188238438Sdteske	f_dialog_title_restore
189238438Sdteske	msg="$msg_is_machine_clock_utc"
190238438Sdteske
191238438Sdteske	if [ "$USE_XDIALOG" ]; then
192238438Sdteske		defaultno="default-no"
193238438Sdteske		height=10 width=77
194238438Sdteske	else
195238438Sdteske		defaultno="defaultno"
196238438Sdteske		height=7 width=73
197238438Sdteske	fi
198238438Sdteske
199238438Sdteske	if [ "$USE_XDIALOG" ]; then
200238438Sdteske		$DIALOG \
201238438Sdteske			--title "$title"         \
202238438Sdteske			--backtitle "$btitle"    \
203238438Sdteske			--$defaultno             \
204238438Sdteske			--ok-label "$msg_yes"    \
205238438Sdteske			--cancel-label "$msg_no" \
206238438Sdteske			--yesno "$msg" $height $width
207238438Sdteske		result=$?
208238438Sdteske	else
209238438Sdteske		$DIALOG \
210238438Sdteske			--title "$title"       \
211238438Sdteske			--backtitle "$btitle"  \
212238438Sdteske			--$defaultno           \
213238438Sdteske			--yes-label "$msg_yes" \
214238438Sdteske			--no-label "$msg_no"   \
215238438Sdteske			--yesno "$msg" $height $width
216238438Sdteske		result=$?
217238438Sdteske	fi
218238438Sdteske
219238438Sdteske	if [ $result -eq 0 ]; then
220238438Sdteske		# User chose YES
221238438Sdteske		[ "$REALLYDOIT" ] &&
222238438Sdteske			f_quietly rm -f "$_PATH_WALL_CMOS_CLOCK"
223238438Sdteske	else
224238438Sdteske		# User chose NO, pressed ESC (or Ctrl-C), or closed box
225238438Sdteske		[ "$REALLYDOIT" ] &&
226238438Sdteske			( umask 222 && :> "$_PATH_WALL_CMOS_CLOCK" )
227238438Sdteske	fi
228238438Sdteskefi
229238438Sdteske
230238438Sdteske#
231238438Sdteske# Process optional default zone argument
232238438Sdteske#
233238438Sdteskeif [ $# -ge 1 ]; then
234238438Sdteske	default="$1"
235238438Sdteske
236238438Sdteske	f_dialog_title "$msg_default_zone_provided"
237238438Sdteske	title="$DIALOG_TITLE"
238238438Sdteske	btitle="$DIALOG_BACKTITLE"
239238438Sdteske	f_dialog_title_restore
240238438Sdteske	msg=$( printf "\n$msg_use_default_zone" "$default" )
241238438Sdteske	size=$( f_dialog_buttonbox_size "$title" "$btitle" "$msg" )
242238438Sdteske
243238438Sdteske	if [ "$USE_XDIALOG" ]; then
244238438Sdteske		eval $DIALOG \
245238438Sdteske			--title \"\$title\"         \
246238438Sdteske			--backtitle \"\$btitle\"    \
247238438Sdteske			--ok-label \"\$msg_yes\"    \
248238438Sdteske			--cancel-label \"\$msg_no\" \
249238438Sdteske			--yesno \"\$msg\" $size
250238438Sdteske		result=$?
251238438Sdteske	else
252238438Sdteske		eval $DIALOG \
253238438Sdteske			--title \"\$title\"       \
254238438Sdteske			--backtitle \"\$btitle\"  \
255238438Sdteske			--yes-label \"\$msg_yes\" \
256238438Sdteske			--no-label \"\$msg_no\"   \
257238438Sdteske			--yesno \"\$msg\" $size
258238438Sdteske		result=$?
259238438Sdteske	fi
260238438Sdteske
261238438Sdteske	if [ $result -eq 0 ]; then
262238438Sdteske		# User chose YES
263238438Sdteske		f_install_zoneinfo_file "$default"
264238438Sdteske		result=$?
265238438Sdteske		[ ! "$USE_XDIALOG" ] && f_dialog_clear
266238438Sdteske		exit $result
267238438Sdteske	fi
268238438Sdteske
269238438Sdteske	[ ! "$USE_XDIALOG" ] && f_dialog_clear
270238438Sdteskefi
271238438Sdteske
272238438Sdteske#
273238438Sdteske# Override the user-supplied umask
274238438Sdteske#
275238438Sdteskeumask 022
276238438Sdteske
277238438Sdteske#
278238438Sdteske# Read databases and perform initialization
279238438Sdteske#
280238438Sdteskef_read_iso3166_table # creates $COUNTRIES and $country_*_name
281238438Sdteskef_read_zones         # creates $country_*_{descr,cont,filename}
282238438Sdteskef_sort_countries     # sorts the countries listed for each continent
283238438Sdteskef_make_menus         # creates $continent_menu_list and $continent_*_menu_list
284238438Sdteske
285238438Sdteske#
286238438Sdteske# Launch application main menu
287238438Sdteske#
288238438SdteskeNEED_CONTINENT=1
289238438SdteskeNEED_COUNTRY=1
290238438Sdteskewhile :; do
291238438Sdteske	if [ "$NEED_CONTINENT" ]; then
292238438Sdteske		dialog_menu_main # prompt the user to select a continent/ocean
293238438Sdteske		retval=$?
294238438Sdteske		mtag=$( f_dialog_menutag )
295238438Sdteske
296238438Sdteske		if [ $retval -ne 0 ]; then
297238438Sdteske			[ "$TZ_OR_FAIL" ] && f_die
298238438Sdteske			exit $SUCCESS
299238438Sdteske		fi
300238438Sdteske
301238438Sdteske		NEED_CONTINENT=
302238438Sdteske
303238438Sdteske		continent=$( eval f_dialog_menutag2item \"\$mtag\" \
304238438Sdteske		                  	$continent_menu_list )
305238438Sdteske		cont=$( f_find_continent "$continent" )
306238438Sdteske		cont_title=$( f_continent $cont title )
307238438Sdteske		nitems=$( f_continent $cont nitems )
308238438Sdteske		isocean=$( f_OCEANP $cont )
309238438Sdteske	fi
310238438Sdteske
311238438Sdteske	if [ "$NEED_COUNTRY" ]; then
312238438Sdteske		if [ "$cont_title" = "$continent_utc_title" ]; then
313238438Sdteske			if f_set_zone_utc; then
314238438Sdteske				break
315238438Sdteske			else
316238438Sdteske				NEED_CONTINENT=1
317238438Sdteske				continue
318238438Sdteske			fi
319238438Sdteske		fi
320238438Sdteske
321238438Sdteske		#
322238438Sdteske		# Short cut -- if there's only one country, don't post a menu.
323238438Sdteske		#
324238438Sdteske		if [ $nitems -eq 1 ]; then
325238438Sdteske			tag=1
326238438Sdteske		else
327238438Sdteske			#
328238438Sdteske			# It's amazing how much good grammar really matters...
329238438Sdteske			#
330238438Sdteske			if [ ! "$isocean" ]; then
331238438Sdteske				title=$( printf "$msg_country_title" \
332238438Sdteske				                "$cont_title" )
333238438Sdteske				f_dialog_title "$title"
334238438Sdteske				title="$DIALOG_TITLE"
335238438Sdteske				btitle="$DIALOG_BACKTITLE"
336238438Sdteske				f_dialog_title_restore
337238438Sdteske				prompt="$msg_select_country"
338238438Sdteske			else
339238438Sdteske				title=$( printf "$msg_island_and_group_title" \
340238438Sdteske				                "$cont_title" )
341238438Sdteske				f_dialog_title "$title"
342238438Sdteske				title="$DIALOG_TITLE"
343238438Sdteske				btitle="$DIALOG_BACKTITLE"
344238438Sdteske				f_dialog_title_restore
345238438Sdteske				prompt="$msg_select_island_or_group"
346238438Sdteske			fi
347238438Sdteske
348238438Sdteske			#
349238438Sdteske			# Calculate size of menu
350238438Sdteske			#
351238438Sdteske			menu_list=$( f_continent $cont menu_list )
352238438Sdteske			size=$( eval f_dialog_menu_size \
353238438Sdteske			        	\"\$title\"  \
354238438Sdteske			        	\"\$btitle\" \
355238438Sdteske			        	\"\$prompt\" \
356238438Sdteske			        	\"\"         \
357238438Sdteske			        	$menu_list   )
358238438Sdteske
359238438Sdteske			#
360238438Sdteske			# Launch the country selection menu
361238438Sdteske			#
362240768Sdteske			dialog_menu=$( eval $DIALOG \
363238438Sdteske				--title \"\$title\"             \
364238438Sdteske				--backtitle \"\$btitle\"        \
365238438Sdteske				--ok-label \"\$msg_ok\"         \
366238438Sdteske				--cancel-label \"\$msg_cancel\" \
367238438Sdteske				--menu \"\$prompt\" $size       \
368238438Sdteske				$menu_list                      \
369240768Sdteske				2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
370240768Sdteske			)
371238438Sdteske			retval=$?
372240768Sdteske			setvar DIALOG_MENU_$$ "$dialog_menu"
373238438Sdteske			tag=$( f_dialog_menutag )
374238438Sdteske
375238438Sdteske			if [ $retval -ne 0 ]; then
376238438Sdteske				NEED_CONTINENT=1
377238438Sdteske				continue # back to main menu
378238438Sdteske			fi
379238438Sdteske		fi
380238438Sdteske
381238438Sdteske		# Get the country code from the user's selection 
382238438Sdteske		tlc=$( f_continent $cont tlc_$tag )
383238438Sdteske
384238438Sdteske		NEED_COUNTRY=
385238438Sdteske	fi
386238438Sdteske
387238438Sdteske	#
388238438Sdteske	# If the selection has only one zone (nzones == -1),
389238438Sdteske	# just set it.
390238438Sdteske	#
391238438Sdteske	nzones=$( f_country $tlc nzones )
392238438Sdteske	if [ $nzones -lt 0 ]; then
393238438Sdteske		real_cont=$( f_country $tlc cont )
394238438Sdteske		real_continent=$( f_continent $real_cont name )
395238438Sdteske		name=$( f_country $tlc name )
396238438Sdteske		filename=$( f_country $tlc filename )
397238438Sdteske
398238438Sdteske		if ! f_confirm_zone "$real_continent/$filename"; then
399238438Sdteske			[ $nitems -eq 1 ] && NEED_CONTINENT=1
400238438Sdteske			NEED_COUNTRY=1
401238438Sdteske			continue
402238438Sdteske		fi
403238438Sdteske	else
404238438Sdteske		title=$( printf "$msg_country_time_zones" \
405238438Sdteske		                "$( f_country $tlc name )" )
406238438Sdteske		f_dialog_title "$title"
407238438Sdteske		title="$DIALOG_TITLE"
408238438Sdteske		btitle="$DIALOG_BACKTITLE"
409238438Sdteske		f_dialog_title_restore
410238438Sdteske		prompt="$msg_select_zone"
411238438Sdteske		menu_list=$( f_country $tlc menu_list )
412238438Sdteske		size=$( eval f_dialog_menu_size \"\$title\"  \"\$btitle\" \
413238438Sdteske		        	\"\$prompt\" \"\" $menu_list )
414238438Sdteske
415238438Sdteske		#
416238438Sdteske		# Launch the zone selection menu
417238438Sdteske		# NOTE: This is as deep as we go
418238438Sdteske		#
419240768Sdteske		dialog_menu=$( eval $DIALOG \
420238438Sdteske			--title \"\$title\"             \
421238438Sdteske			--backtitle \"\$btitle\"        \
422238438Sdteske			--ok-label \"\$msg_ok\"         \
423238438Sdteske			--cancel-label \"\$msg_cancel\" \
424238438Sdteske			--menu \"\$prompt\" $size       \
425238438Sdteske			$menu_list                      \
426240768Sdteske			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
427240768Sdteske		)
428238438Sdteske		retval=$?
429240768Sdteske		setvar DIALOG_MENU_$$ "$dialog_menu"
430238438Sdteske		n=$( f_dialog_menutag )
431238438Sdteske
432238438Sdteske		if [ $retval -ne 0 ]; then
433238438Sdteske			[ $nitems -eq 1 ] && NEED_CONTINENT=1
434238438Sdteske			NEED_COUNTRY=1
435238438Sdteske			continue
436238438Sdteske		fi
437238438Sdteske
438238438Sdteske		real_cont=$( f_country $tlc cont_$n )
439238438Sdteske		real_continent=$( f_continent $real_cont name )
440238438Sdteske		name=$( f_country $tlc name )
441238438Sdteske		filename=$( f_country $tlc filename_$n )
442238438Sdteske
443238438Sdteske		f_confirm_zone "$real_continent/$filename" || continue
444238438Sdteske	fi
445238438Sdteske
446238438Sdteske	[ $retval -eq 0 ] || continue # back to main menu
447238438Sdteske
448238438Sdteske	if ! f_install_zoneinfo "$real_continent/$filename"; then
449238438Sdteske		[ $nzones -lt 0 ] && NEED_COUNTRY=1
450238438Sdteske	else
451238438Sdteske		break
452238438Sdteske	fi
453238438Sdteskedone
454238438Sdteske
455238438Sdteske################################################################################
456238438Sdteske# END
457238438Sdteske################################################################################
458