usr/src/lib/liborchestrator/locale.c
changeset 0 87f703f8362e
child 26 fb9b1fd08e73
equal deleted inserted replaced
-1:000000000000 0:87f703f8362e
       
     1 /*
       
     2  * CDDL HEADER START
       
     3  *
       
     4  * The contents of this file are subject to the terms of the
       
     5  * Common Development and Distribution License (the "License").
       
     6  * You may not use this file except in compliance with the License.
       
     7  *
       
     8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
       
     9  * or http://www.opensolaris.org/os/licensing.
       
    10  * See the License for the specific language governing permissions
       
    11  * and limitations under the License.
       
    12  *
       
    13  * When distributing Covered Code, include this CDDL HEADER in each
       
    14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
       
    15  * If applicable, add the following below this CDDL HEADER, with the
       
    16  * fields enclosed by brackets "[]" replaced with your own identifying
       
    17  * information: Portions Copyright [yyyy] [name of copyright owner]
       
    18  *
       
    19  * CDDL HEADER END
       
    20  */
       
    21 /*
       
    22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
       
    23  * Use is subject to license terms.
       
    24  */
       
    25 
       
    26 #pragma ident	"@(#)locale.c	1.3	07/08/27 SMI"
       
    27 
       
    28 #include <fcntl.h>
       
    29 #include <stdio.h>
       
    30 #include <stdlib.h>
       
    31 #include <string.h>
       
    32 #include <sys/types.h>
       
    33 #include <unistd.h>
       
    34 #include <stropts.h>
       
    35 #include <sys/kbio.h>
       
    36 #include <stdio.h>
       
    37 #include <libintl.h>
       
    38 #include <locale.h>
       
    39 #include <malloc.h>
       
    40 #include <string.h>
       
    41 #include <sys/types.h>
       
    42 #include <sys/uio.h>
       
    43 #include <unistd.h>
       
    44 #include <stdlib.h>
       
    45 #include <sys/param.h>
       
    46 #include <sys/stat.h>
       
    47 #include <errno.h>
       
    48 #include <dirent.h>
       
    49 #include <ctype.h>
       
    50 
       
    51 #include "spmicommon_api.h"
       
    52 #include "orchestrator_private.h"
       
    53 #include "orchestrator_lang_codes.h"
       
    54 
       
    55 #define	COUNTRY_SEP	'_'
       
    56 #define	CODESET_SEP	'.'
       
    57 #define	UTF		"UTF-8"
       
    58 
       
    59 #define	SIMPLIFIED_CHINESE	"Chinese-Simplified"
       
    60 #define	TRADITIONAL_CHINESE	"Chinese-Traditional"
       
    61 
       
    62 #define	INSTALL_NLS_PATH	"/usr/lib/install/data/lib/locale"
       
    63 #define	NLS_PATH		"/usr/lib/locale"
       
    64 
       
    65 
       
    66 /* Static variables used to store language/locale system information */
       
    67 
       
    68 static	lang_info_t 	*install_ll_list = NULL;	/* lang, locale list */
       
    69 static	lang_info_t	*supported_ll_list = NULL;
       
    70 static	char		*install_lang_list[MAX_NUM_LANG];
       
    71 static	char		*supported_lang_list[MAX_NUM_LANG];
       
    72 static	char		**install_languages = NULL;	/* sorted list */
       
    73 static	char		**supported_languages = NULL;
       
    74 static	char		*app_locale = NULL;
       
    75 static	int		lang_initialized = 0;
       
    76 static	int		install_initialized = 0;
       
    77 static	int		install_lang_total = 0;
       
    78 static	int		supported_lang_total = 0;
       
    79 
       
    80 struct	chinese_values {
       
    81 	char 	*lang;
       
    82 	char	*lang_name;
       
    83 	char	*lang_code;
       
    84 } chinese_values[] = {
       
    85 	{"zh", SIMPLIFIED_CHINESE, "sc"},
       
    86 	{"zh.GBK", SIMPLIFIED_CHINESE, "sc"},
       
    87 	{"zh.UTF-8", SIMPLIFIED_CHINESE, "sc"},
       
    88 	{"zh_CN", "SIMPLIFIED_CHINESE", "sc"},
       
    89 	{"zh_CN.GB18030", SIMPLIFIED_CHINESE, "sc"},
       
    90 	{"zh_HK", TRADITIONAL_CHINESE, "tc"},
       
    91 	{"zh_HK.BIG5HK", TRADITIONAL_CHINESE, "tc"},
       
    92 	{"zh_HK.UTF-8", TRADITIONAL_CHINESE, "tc"},
       
    93 	{"zh_TW", TRADITIONAL_CHINESE, "tc"},
       
    94 	{"zh_TW.BIG5", TRADITIONAL_CHINESE, "tc"},
       
    95 	{"zh_TW.UTF-8", TRADITIONAL_CHINESE, "tc"}
       
    96 };
       
    97 
       
    98 
       
    99 static int 	add_lang_to_list(char ***list, char *locale, int *k, int j);
       
   100 static void 	add_locale_entry_to_lang(lang_info_t *lp, char *locale,
       
   101     char *region, boolean_t is_default);
       
   102 static int	build_language_list(char *path, char **, int *);
       
   103 static void	build_install_ll_list(char *nlspath, char **list,
       
   104     int lang_total, lang_info_t **return_list, int *ll_total);
       
   105 static void	build_ll_list(char **list, int lang_total,
       
   106 		    lang_info_t **, int *total);
       
   107 static	char	*copy_up_to(char *start, char *t);
       
   108 static int	create_lang_entry(char *lang, char *locale, char *region,
       
   109     lang_info_t **, boolean_t is_default);
       
   110 static void	end_of_comp(char **t, char **start);
       
   111 static char 	**get_actual_languages(char **list, int *);
       
   112 static lang_info_t *get_lang_entry(char *, lang_info_t *search_list);
       
   113 static char 	*get_locale_component(char **t, char **start);
       
   114 static char 	*get_locale_description(char *lang, char *region);
       
   115 static int 	handle_chinese_language(char *region, char **lang);
       
   116 static boolean_t is_locale_in_installer_lang(char *locale_name);
       
   117 static boolean_t is_valid_locale(char *locale);
       
   118 static int 	list_cmp(const void *p1, const void *p2);
       
   119 static int 	lang_init(char *path, char **list, int *total, int *init_var);
       
   120 static int 	save_system_default_locale(char *locale);
       
   121 static void 	set_lang(char *locale);
       
   122 static void 	set_lc(char *, char *, char *, char *, char *, char *);
       
   123 static char 	*strip_comment(char *buf);
       
   124 static char 	*translate_description(char *locale, char *desc);
       
   125 static void 	translate_lang_names(lang_info_t **list);
       
   126 static void 	sort_lang_list(char **unsorted_list, int total);
       
   127 static char 	*substitute_chinese_language(char *locale, char **code);
       
   128 static char 	*substitute_C_POSIX_language(char **code);
       
   129 static void 	update_init(FILE *fp, char *locale);
       
   130 static void 	update_env(char *locale);
       
   131 
       
   132 #define	STR_LANG	"LANG="
       
   133 #define	LEN_LANG	(sizeof (STR_LANG) - 1)
       
   134 #define	STR_LC_COLLATE	"LC_COLLATE="
       
   135 #define	LEN_LC_COLLATE	(sizeof (STR_LC_COLLATE) - 1)
       
   136 #define	STR_LC_CTYPE	"LC_CTYPE="
       
   137 #define	LEN_LC_CTYPE	(sizeof (STR_LC_CTYPE) - 1)
       
   138 #define	STR_LC_MESSAGES	"LC_MESSAGES="
       
   139 #define	LEN_LC_MESSAGES	(sizeof (STR_LC_MESSAGES) - 1)
       
   140 #define	STR_LC_MONETARY	"LC_MONETARY="
       
   141 #define	LEN_LC_MONETARY	(sizeof (STR_LC_MONETARY) - 1)
       
   142 #define	STR_LC_NUMERIC	"LC_NUMERIC="
       
   143 #define	LEN_LC_NUMERIC	(sizeof (STR_LC_NUMERIC) - 1)
       
   144 #define	STR_LC_TIME	"LC_TIME="
       
   145 #define	LEN_LC_TIME	(sizeof (STR_LC_TIME) - 1)
       
   146 
       
   147 
       
   148 /*
       
   149  * om_get_install_lang_info
       
   150  * This function returns the locales available for use in setting
       
   151  * installer locale.
       
   152  * Input:	None
       
   153  * Output:	int *total, returns the total number of locales found
       
   154  * Return:	Pointer to lang_info_t which is a linked list of
       
   155  *		locales available for selection.
       
   156  *		NULL if no locales found.
       
   157  * Error Handling:
       
   158  *		OM_SUCCESS if locales found.
       
   159  *		OM_FAILIRE if no locales found.
       
   160  */
       
   161 lang_info_t *
       
   162 om_get_install_lang_info(int *total)
       
   163 {
       
   164 	int		ll_total;
       
   165 	int		ret;
       
   166 
       
   167 	/*
       
   168 	 * Path to look for locale data.
       
   169 	 */
       
   170 	*total = 0;
       
   171 	/*
       
   172 	 * Build the lang list for the install application support.
       
   173 	 */
       
   174 	if (!install_initialized) {
       
   175 		ret = lang_init(INSTALL_NLS_PATH, (char **)&install_lang_list,
       
   176 		    &install_lang_total, &install_initialized);
       
   177 		if (ret)
       
   178 			return (NULL);
       
   179 	}
       
   180 
       
   181 	/*
       
   182 	 * For the install languages we build the locale list associated
       
   183 	 * with them by reading the lcctab file in the /usr/lib/locale/
       
   184 	 * directory.
       
   185 	 */
       
   186 	build_install_ll_list(NLS_PATH, (char **)&install_lang_list,
       
   187 	    install_lang_total, &install_ll_list, &ll_total);
       
   188 	*total = ll_total;
       
   189 	return (install_ll_list);
       
   190 }
       
   191 
       
   192 /*
       
   193  * om_get_install_lang_names
       
   194  * This function returns the lang names available for use in setting
       
   195  * installer locale system
       
   196  * Input:	None
       
   197  * Output:	int *total, returns the total number of locales found
       
   198  * Return:	char ** list of lang names available for selection.
       
   199  *		NULL if no locales found.
       
   200  * Error Handling:
       
   201  *		OM_SUCCESS if locales found.
       
   202  *		OM_FAILIRE if no locales found.
       
   203  */
       
   204 char **
       
   205 om_get_install_lang_names(int *total)
       
   206 {
       
   207 	int		ret;
       
   208 	*total = 0;
       
   209 
       
   210 	/*
       
   211 	 * Reads directory that contains installation application
       
   212 	 * languages. Fills install_lang_list with this data,
       
   213 	 * if this has not been initialized yet.
       
   214 	 */
       
   215 	if (!install_initialized) {
       
   216 		ret = lang_init(INSTALL_NLS_PATH, (char **)&install_lang_list,
       
   217 		    &install_lang_total, &install_initialized);
       
   218 		if (ret)
       
   219 			return (NULL);
       
   220 	}
       
   221 	install_languages = get_actual_languages((char **)install_lang_list,
       
   222 	    total);
       
   223 	sort_lang_list(install_languages, *total);
       
   224 	return (install_languages);
       
   225 }
       
   226 
       
   227 /*
       
   228  * om_get_lang_info
       
   229  * This function returns the available locales for installation on to
       
   230  * system
       
   231  * Input:	None
       
   232  * Output:	int *total, returns the total number of locales found
       
   233  * Return:	Pointer to lang_info_t which is a linked list of
       
   234  *		locales available for selection to install.
       
   235  *		NULL if no locales found.
       
   236  * Error Handling:
       
   237  *		OM_SUCCESS if locales found.
       
   238  *		OM_FAILIRE if no locales found.
       
   239  */
       
   240 lang_info_t *
       
   241 om_get_lang_info(int *total)
       
   242 {
       
   243 	int	ret;
       
   244 	int	locale_total;
       
   245 
       
   246 	*total = 0;
       
   247 
       
   248 	if (!lang_initialized) {
       
   249 		ret = lang_init(NLS_PATH, (char **)&supported_lang_list,
       
   250 		    &supported_lang_total, &lang_initialized);
       
   251 		if (ret)
       
   252 			return (NULL);
       
   253 	}
       
   254 	/*
       
   255 	 * This function looks in usr/lib/locale on the installation
       
   256 	 * media to determine languages that we provide support for.
       
   257 	 */
       
   258 	sort_lang_list((char **)&supported_lang_list, supported_lang_total);
       
   259 	build_ll_list((char **)&supported_lang_list, supported_lang_total,
       
   260 	    &supported_ll_list, &locale_total);
       
   261 	*total = locale_total;
       
   262 	return (supported_ll_list);
       
   263 }
       
   264 
       
   265 /*
       
   266  * om_get_lang_names
       
   267  * This function returns the language strings that can are supported for
       
   268  * installation on to system.
       
   269  * Input:	None
       
   270  * Output:	int *total, returns the total number of lang names found
       
   271  * Return:	char ** list of lang names
       
   272  *		NULL if no lang names found.
       
   273  * Error Handling:
       
   274  *		OM_SUCCESS if locales found.
       
   275  *		OM_FAILURE if no locales found.
       
   276  */
       
   277 
       
   278 char **
       
   279 om_get_lang_names(int *total)
       
   280 {
       
   281 	int	ret = 0;
       
   282 	*total = 0;
       
   283 
       
   284 	/*
       
   285 	 * We only gather 'supported lang names'. Supported means
       
   286 	 * full locale, UTF-8 only. For display to the user for
       
   287 	 * default locale selection.
       
   288 	 */
       
   289 	if (!lang_initialized) {
       
   290 		ret = lang_init(NLS_PATH, (char **)&supported_lang_list,
       
   291 		    &supported_lang_total, &lang_initialized);
       
   292 		if (ret) {
       
   293 			return (NULL);
       
   294 		}
       
   295 	}
       
   296 	supported_languages = get_actual_languages(supported_lang_list, total);
       
   297 	sort_lang_list(supported_languages, *total);
       
   298 	return (supported_languages);
       
   299 }
       
   300 
       
   301 /*
       
   302  * om_get_locale_info
       
   303  * This function returns a linked list of locale_info_t's that correspond
       
   304  * to the language specified.
       
   305  * Input:	char *lang - language for which to return locale data.
       
   306  * Output:	int *total, returns the total number of lang names found
       
   307  * Return:	locale_info_t * list of locale_names.
       
   308  *		NULL if no locale names found.
       
   309  * Error Handling:
       
   310  *		OM_SUCCESS if locales found.
       
   311  *		OM_FAILURE if no locales found.
       
   312  */
       
   313 locale_info_t *
       
   314 om_get_locale_info(char *lang, int *total)
       
   315 {
       
   316 	lang_info_t *langp;
       
   317 	locale_info_t *localep = NULL;
       
   318 	lang_info_t	*tmp = supported_ll_list;
       
   319 
       
   320 	if (tmp == NULL)
       
   321 		tmp = install_ll_list;
       
   322 	if (tmp == NULL)
       
   323 		return (NULL);
       
   324 
       
   325 	/*
       
   326 	 * The lang is passed in as the lang code. Not the translated
       
   327 	 * name.
       
   328 	 */
       
   329 	for (langp = tmp; langp != NULL; langp = langp->next) {
       
   330 		if (strcmp(langp->lang, lang) == 0) {
       
   331 			localep = langp->locale_info;
       
   332 			break;
       
   333 		}
       
   334 	}
       
   335 	*total = langp->n_locales;
       
   336 	return (localep);
       
   337 }
       
   338 
       
   339 /*
       
   340  * om_get_locale_names
       
   341  * This function returns a list of locale names that correspond
       
   342  * to the language specified.
       
   343  * Input:	char *lang - language for which to return locale data.
       
   344  * Output:	int *total, returns the total number of lang names found
       
   345  * Return:	char ** list of locale_names.
       
   346  *		NULL if no locale names found.
       
   347  * Error Handling:
       
   348  *		OM_SUCCESS if locales found.
       
   349  *		OM_FAILURE if no locales found.
       
   350  */
       
   351 char **
       
   352 om_get_locale_names(char *lang, int *total)
       
   353 {
       
   354 	lang_info_t 	*langp;
       
   355 	locale_info_t 	*localep = NULL;
       
   356 	char		**locale_names;
       
   357 	int		i = 0;
       
   358 
       
   359 	/*
       
   360 	 * locale_names is a an array of char *. Allocate each array
       
   361 	 * member before strduping the locale_info in to this array.
       
   362 	 */
       
   363 
       
   364 	/*
       
   365 	 * The lang is passed in as the lang code. Not the translated
       
   366 	 * name.
       
   367 	 */
       
   368 	for (langp = supported_ll_list; langp != NULL; langp = langp->next) {
       
   369 		if (strcmp(langp->lang, lang) == 0) {
       
   370 			localep = langp->locale_info;
       
   371 			break;
       
   372 		}
       
   373 	}
       
   374 	/*
       
   375 	 * allocate number of char * pointers to correspond to number
       
   376 	 * of locale names.
       
   377 	 */
       
   378 	locale_names = (char **)malloc(langp->n_locales * sizeof (char *));
       
   379 	if (locale_names == NULL) {
       
   380 		om_set_error(OM_NO_SPACE);
       
   381 		return (NULL);
       
   382 	}
       
   383 
       
   384 	for (; localep; localep = localep->next) {
       
   385 		locale_names[i] = strdup(localep->locale_name);
       
   386 		if (locale_names[i] == NULL) {
       
   387 			om_free_lang_names(locale_names);
       
   388 			om_set_error(OM_NO_SPACE);
       
   389 			return (NULL);
       
   390 		}
       
   391 		i++;
       
   392 	}
       
   393 	*total = i;
       
   394 	return (locale_names);
       
   395 }
       
   396 
       
   397 /*
       
   398  * om_set_install_lang_by_value
       
   399  * This function sets the installer application language, using the
       
   400  * lang_info_t * data passed in.
       
   401  * Input:	lang_info_t	* lang/locale info to set
       
   402  * Output:	none
       
   403  * Return:	Success or Failure
       
   404  * Error Handling:
       
   405  *		OM_SUCCESS if locales found.
       
   406  *		OM_FAILURE if no locales found.
       
   407  */
       
   408 int
       
   409 om_set_install_lang_by_value(lang_info_t *localep)
       
   410 {
       
   411 	/*
       
   412 	 * For install applications, there will only be 1 locale
       
   413 	 * associated with that language.
       
   414 	 */
       
   415 	locale_info_t *locp = localep->locale_info;
       
   416 	if (locp == NULL) {
       
   417 		om_set_error(OM_INVALID_LOCALE);
       
   418 		return (OM_FAILURE);
       
   419 	}
       
   420 
       
   421 	om_save_locale(locp->locale_name, B_TRUE);
       
   422 	return (OM_SUCCESS);
       
   423 }
       
   424 
       
   425 /*
       
   426  * om_set_install_lang_by_name
       
   427  * This function sets the installer application language, using the
       
   428  * lang name passed in.
       
   429  * Input:	char *lang name to set.
       
   430  * Output:	none
       
   431  * Return:	int, Success or Failure
       
   432  * Error Handling:
       
   433  *		OM_SUCCESS if locales found.
       
   434  *		OM_FAILURE if no locales found.
       
   435  */
       
   436 int
       
   437 om_set_install_lang_by_name(char *lang)
       
   438 {
       
   439 	locale_info_t	*locp;
       
   440 	int		total;
       
   441 	/*
       
   442 	 * Find the locale entry based on the name passed in. If no
       
   443 	 * locales for this language use the default locale of C/POSIX.
       
   444 	 */
       
   445 	locp = om_get_locale_info(lang, &total);
       
   446 
       
   447 	if (locp == NULL) {
       
   448 		om_set_error(OM_INVALID_LOCALE);
       
   449 		return (OM_FAILURE);
       
   450 	}
       
   451 
       
   452 	/*
       
   453 	 * Now, set the environment for the installation application.
       
   454 	 */
       
   455 	om_save_locale(locp->locale_name, B_TRUE);
       
   456 	om_free_locale_info(locp);
       
   457 	return (OM_SUCCESS);
       
   458 }
       
   459 
       
   460 /*
       
   461  * om_set_default_locale_by_name
       
   462  * This function sets the system default locale by name
       
   463  * Input:	char *lang name to set.
       
   464  * Output:	none
       
   465  * Return:	int, Success or Failure
       
   466  * Error Handling:
       
   467  *		OM_SUCCESS if locales found.
       
   468  *		OM_FAILURE if no locales found.
       
   469  */
       
   470 int
       
   471 om_set_default_locale_by_name(char *localep)
       
   472 {
       
   473 	int ret = 0;
       
   474 
       
   475 	/*
       
   476 	 * C/Posix is the default, there is no need to specify it
       
   477 	 * in the /etc/default/init file.
       
   478 	 */
       
   479 	if (strcasecmp(localep, "C/Posix") == 0 ||
       
   480 	    strcasecmp(localep, "Posix") == 0) {
       
   481 		return (ret);
       
   482 	}
       
   483 	ret = save_system_default_locale(localep);
       
   484 	if (!ret)
       
   485 		om_save_locale(localep, B_FALSE);
       
   486 	return (ret);
       
   487 }
       
   488 
       
   489 /*
       
   490  * om_get_default_locale
       
   491  * This function returns the default locale as set by a call to
       
   492  * set_default_locale.
       
   493  * Input:	locale_info_t *loclistp - list to search
       
   494  * Output:	none
       
   495  * Return:	locale_info_t * pointer to structure for default locale.
       
   496  * 		or NULL if none found.
       
   497  * Error Handling:
       
   498  *		OM_SUCCESS if locales found.
       
   499  *		OM_FAILURE if no locales found.
       
   500  */
       
   501 locale_info_t *
       
   502 om_get_def_locale(locale_info_t *loclistp)
       
   503 {
       
   504 	locale_info_t *lp;
       
   505 
       
   506 	for (lp = loclistp; lp != NULL; lp = lp->next)
       
   507 		if (lp->def_locale == B_TRUE)
       
   508 			return (lp);
       
   509 	return (NULL);
       
   510 }
       
   511 /*
       
   512  * om_free_lang_names
       
   513  * This function frees the memory associated with the char **list of lang
       
   514  * names passed in.
       
   515  * Input:	char **lang name list.
       
   516  * Output:	none
       
   517  * Return:	none
       
   518  * Error Handling:
       
   519  *		none
       
   520  */
       
   521 void
       
   522 om_free_lang_names(char **listp)
       
   523 {
       
   524 	int	i = 0;
       
   525 
       
   526 	for (i = 0; listp[i] != NULL; i++) {
       
   527 		free(listp[i]);
       
   528 	}
       
   529 	free(listp);
       
   530 }
       
   531 
       
   532 /*
       
   533  * om_free_lang_info
       
   534  * This function frees the memory associated with the lang_info_t *list
       
   535  * Input:	lang_info_t * langp - list to free
       
   536  * Output:	none
       
   537  * Return:	none
       
   538  * Error Handling:
       
   539  *		none
       
   540  */
       
   541 void
       
   542 om_free_lang_info(lang_info_t *langp)
       
   543 {
       
   544 	lang_info_t *nextp;
       
   545 
       
   546 	while (langp != NULL) {
       
   547 		nextp = langp->next;
       
   548 		om_free_locale_info((locale_info_t *)langp->locale_info);
       
   549 		free(langp->lang);
       
   550 		free(langp->lang_name);
       
   551 		free(langp);
       
   552 		langp = nextp;
       
   553 	}
       
   554 }
       
   555 
       
   556 /*
       
   557  * om_free_locale_info
       
   558  * This function frees the memory associated with the locale_info_t *list
       
   559  * Input:	locale_info_t * localep - list to free
       
   560  * Output:	none
       
   561  * Return:	none
       
   562  * Error Handling:
       
   563  *		none
       
   564  */
       
   565 void
       
   566 om_free_locale_info(locale_info_t *localep)
       
   567 {
       
   568 	locale_info_t	*nextp;
       
   569 
       
   570 	while (localep != NULL) {
       
   571 		nextp = localep->next;
       
   572 		free(localep->locale_name);
       
   573 		free(localep->locale_desc);
       
   574 		free(localep);
       
   575 		localep = nextp;
       
   576 	}
       
   577 }
       
   578 /*
       
   579  * Static functions.
       
   580  */
       
   581 static int
       
   582 save_system_default_locale(char *locale)
       
   583 {
       
   584 
       
   585 	FILE 	*fp = (FILE *)NULL;
       
   586 
       
   587 	if (locale == NULL)
       
   588 		return (OM_FAILURE);
       
   589 
       
   590 	if ((fp = fopen(TMP_INITDEFSYSLOC, "w")) == (FILE *)NULL)
       
   591 		return (OM_FAILURE);
       
   592 	if (fprintf(fp, "%s\n", locale) < 0) {
       
   593 		(void) fclose(fp);
       
   594 		return (OM_FAILURE);
       
   595 	}
       
   596 	(void) fclose(fp);
       
   597 
       
   598 	if ((fp = fopen(TMP_DEFSYSLOC, "w")) == (FILE *)NULL)
       
   599 		return (OM_FAILURE);
       
   600 	if (fprintf(fp, "%s\n", locale) < 0) {
       
   601 		(void) fclose(fp);
       
   602 		return (OM_FAILURE);
       
   603 	}
       
   604 	(void) fclose(fp);
       
   605 	return (OM_SUCCESS);
       
   606 }
       
   607 
       
   608 
       
   609 static int
       
   610 lang_init(char *path, char **list, int *total, int *init_var)
       
   611 {
       
   612 	int	ret;
       
   613 
       
   614 	ret = build_language_list(path, list, total);
       
   615 	if (!ret) {
       
   616 		*init_var = 1;
       
   617 	}
       
   618 	return (ret);
       
   619 }
       
   620 
       
   621 /*
       
   622  * Function
       
   623  *		create_lang_entry
       
   624  *
       
   625  * Description
       
   626  *		Create a language/locale list node and link
       
   627  *		it into the lang/locale linked list.
       
   628  *
       
   629  * Scope
       
   630  *		Private
       
   631  *
       
   632  * Parameters
       
   633  *		lang - language to add
       
   634  *		locale - locale which uses lang
       
   635  *
       
   636  * Return
       
   637  *		none
       
   638  *
       
   639  */
       
   640 static int
       
   641 create_lang_entry(char *lang, char *locale, char *region,
       
   642     lang_info_t **return_list, boolean_t is_default)
       
   643 {
       
   644 	lang_info_t	*tmp, *last, *new;
       
   645 	locale_info_t	*lp = NULL;
       
   646 	char		**trans_lang = NULL;
       
   647 	char		*tmp_lang = NULL;
       
   648 	char		*tmp_locale = NULL;
       
   649 	char		*code = NULL;
       
   650 	char		*desc = NULL;
       
   651 	int		total;
       
   652 	lang_info_t	*list = *return_list;
       
   653 
       
   654 	/*
       
   655 	 * For Chinese we have to handle it specially. There is Traditional
       
   656 	 * Chinese or Simplified Chinese. Everything else is a locale.
       
   657 	 */
       
   658 	if (strncmp(lang, "zh", 2) == 0) {
       
   659 		tmp_lang = strdup(dgettext(TEXT_DOMAIN,
       
   660 		    substitute_chinese_language(lang, &code)));
       
   661 		if (locale == NULL)
       
   662 			tmp_locale = strdup(dgettext(TEXT_DOMAIN, lang));
       
   663 	}
       
   664 	if (strncmp(lang, "C", 1) == 0) {
       
   665 		tmp_lang = strdup(dgettext(TEXT_DOMAIN,
       
   666 		    substitute_C_POSIX_language(&code)));
       
   667 		if (locale == NULL)
       
   668 			tmp_locale = strdup(dgettext(TEXT_DOMAIN, lang));
       
   669 	}
       
   670 
       
   671 	new = (lang_info_t *)malloc(sizeof (lang_info_t));
       
   672 	if (new == NULL)
       
   673 		goto error;
       
   674 
       
   675 	(void) memset(new, 0, sizeof (lang_info_t));
       
   676 
       
   677 	new->lang = (code != NULL) ? strdup(code): strdup(lang);
       
   678 	if (new->lang == NULL)
       
   679 		goto error;
       
   680 
       
   681 	if (tmp_lang != NULL) {
       
   682 		trans_lang = &tmp_lang;
       
   683 	} else
       
   684 		trans_lang = get_actual_languages(&new->lang, &total);
       
   685 
       
   686 	/*
       
   687 	 * We look for the lang name in our list of iso approved language
       
   688 	 * translations. If not found, then it isn't a language so
       
   689 	 * we don't create an entry for it.
       
   690 	 */
       
   691 
       
   692 	if (trans_lang != NULL && *trans_lang != NULL) {
       
   693 		new->lang_name  = *trans_lang;
       
   694 	} else {
       
   695 		om_set_error(OM_NOT_LANG);
       
   696 		goto error;
       
   697 	}
       
   698 
       
   699 	new->def_lang = is_default;
       
   700 
       
   701 	if (locale != NULL || tmp_locale != NULL) {
       
   702 		lp = (locale_info_t *)malloc(sizeof (locale_info_t));
       
   703 		if (lp == NULL) {
       
   704 			om_set_error(OM_NO_SPACE);
       
   705 			goto error;
       
   706 		}
       
   707 		(void) memset(lp, 0, sizeof (locale_info_t));
       
   708 
       
   709 		if (tmp_locale) {
       
   710 			lp->locale_name = tmp_locale;
       
   711 		} else {
       
   712 			lp->locale_name = strdup(locale);
       
   713 		}
       
   714 		if (lp->locale_name == NULL) {
       
   715 			om_set_error(OM_NO_SPACE);
       
   716 			goto error;
       
   717 		}
       
   718 
       
   719 		desc = get_locale_description(new->lang_name, region);
       
   720 		lp->locale_desc = desc;
       
   721 		new->locale_info = lp;
       
   722 		new->locale_info->def_locale = is_default;
       
   723 		new->n_locales++;
       
   724 	}
       
   725 	if (list != NULL) {
       
   726 		for (tmp = list, last = NULL; tmp != NULL;
       
   727 		    last = tmp, tmp = tmp->next) {
       
   728 			/* Everything is after English */
       
   729 			if (strcmp(tmp->lang, dgettext(TEXT_DOMAIN,
       
   730 			    "English")) == 0) {
       
   731 				break;
       
   732 			}
       
   733 			if (strcmp(tmp->lang, lang) > 0) {
       
   734 				break;
       
   735 			}
       
   736 		}
       
   737 		if (tmp == list) {
       
   738 			new->next = list;
       
   739 			list = new;
       
   740 		} else {
       
   741 			last->next = new;
       
   742 			new->next = tmp;
       
   743 		}
       
   744 	} else {
       
   745 		list = new;
       
   746 	}
       
   747 
       
   748 	free(code);
       
   749 	*(return_list) = list;
       
   750 	return (OM_SUCCESS);
       
   751 
       
   752 error:
       
   753 	free(code);
       
   754 	om_free_lang_info(new);
       
   755 	om_free_locale_info(lp);
       
   756 	return (OM_FAILURE);
       
   757 
       
   758 }
       
   759 /*
       
   760  * Function
       
   761  *		get_lang_entry
       
   762  *
       
   763  * Description
       
   764  *		Get the language/locale list node which uses
       
   765  *		the specified language
       
   766  *
       
   767  * Scope
       
   768  *		Private
       
   769  *
       
   770  * Parameters
       
   771  *		lang - language to search for
       
   772  *
       
   773  * Return
       
   774  *		a pointer to the correct lang/locale node or NULL
       
   775  *
       
   776  */
       
   777 static lang_info_t *
       
   778 get_lang_entry(char *lang_name, lang_info_t *search_list)
       
   779 {
       
   780 	lang_info_t 	*list = NULL;
       
   781 	char		*tmp_lang = NULL;
       
   782 	char		*code = NULL;
       
   783 	boolean_t	found = B_FALSE;
       
   784 
       
   785 	if (lang_name == NULL)
       
   786 		return (NULL);
       
   787 	/*
       
   788 	 * Chinese language names are stored differently.
       
   789 	 */
       
   790 
       
   791 	if (strncmp(lang_name, "zh", 2) == 0)  {
       
   792 		tmp_lang = strdup(dgettext(TEXT_DOMAIN,
       
   793 		    substitute_chinese_language(lang_name, &code)));
       
   794 	}
       
   795 
       
   796 	for (list = search_list; list != NULL; list = list->next) {
       
   797 		if (code) {
       
   798 			if (strcmp(list->lang, code) == 0) {
       
   799 				found = B_TRUE;
       
   800 				break;
       
   801 			}
       
   802 		} else {
       
   803 			if (strcmp(list->lang, lang_name) == 0) {
       
   804 				found = B_TRUE;
       
   805 				break;
       
   806 			}
       
   807 		}
       
   808 	}
       
   809 
       
   810 	free(tmp_lang);
       
   811 	free(code);
       
   812 
       
   813 	if (!found)
       
   814 		return (NULL);
       
   815 	return (list);
       
   816 }
       
   817 
       
   818 /*
       
   819  * Function
       
   820  *		add_locale_entry_to_lang
       
   821  *
       
   822  * Description
       
   823  *		Add an additional locale to the list of
       
   824  *		locales that use lang.
       
   825  *
       
   826  * Scope
       
   827  *		Private
       
   828  *
       
   829  * Parameters
       
   830  *		langp - pointer to the lang/locale node to add locale to
       
   831  *		locale - locale which uses lang
       
   832  *
       
   833  * Return
       
   834  *		none
       
   835  *
       
   836  */
       
   837 static void
       
   838 add_locale_entry_to_lang(lang_info_t *langp, char *locale_name, char *region,
       
   839     boolean_t is_default)
       
   840 {
       
   841 	char		*desc = NULL;
       
   842 	locale_info_t 	*locp = NULL;
       
   843 	locale_info_t	*tmp = NULL;
       
   844 
       
   845 	tmp = langp->locale_info;
       
   846 
       
   847 	/*
       
   848 	 * Check for previous inclusion of this locale entry.
       
   849 	 */
       
   850 
       
   851 	while (tmp != NULL) {
       
   852 		if (strcmp(tmp->locale_name, locale_name) == 0)
       
   853 			return;
       
   854 		tmp = tmp->next;
       
   855 	}
       
   856 	/*
       
   857 	 * Allocate space for new entry.
       
   858 	 */
       
   859 	locp = (locale_info_t *)malloc(sizeof (locale_info_t));
       
   860 	if (locp == NULL) {
       
   861 		om_set_error(OM_NO_SPACE);
       
   862 		return;
       
   863 	}
       
   864 	(void) memset(locp, 0, sizeof (locale_info_t));
       
   865 
       
   866 	locp->locale_name = strdup(locale_name);
       
   867 	if (locp->locale_name == NULL) {
       
   868 		om_set_error(OM_NO_SPACE);
       
   869 		om_free_locale_info(locp);
       
   870 		return;
       
   871 	}
       
   872 
       
   873 	desc = get_locale_description(langp->lang_name, region);
       
   874 	locp->locale_desc = desc;
       
   875 	locp->def_locale = is_default;
       
   876 
       
   877 	locp->next = langp->locale_info;
       
   878 	langp->locale_info = locp;
       
   879 	langp->def_lang = is_default;
       
   880 	langp->n_locales++;
       
   881 }
       
   882 
       
   883 static void
       
   884 build_install_ll_list(char *nlspath, char **install_list, int lang_total,
       
   885     lang_info_t **return_list, int *ll_total)
       
   886 {
       
   887 	char 		path[MAXPATHLEN];
       
   888 	char		trans[MAX_LOCALE + 1];
       
   889 	char 		linebuf[128];
       
   890 	FILE		*fp;
       
   891 	char		*c, *c2;
       
   892 	int		i, ret = 0;
       
   893 	lang_info_t	*lp;
       
   894 	locale_info_t	*locp = NULL;
       
   895 	int		num_entries = 0;
       
   896 	boolean_t	is_default = B_FALSE;
       
   897 	char		*start = NULL, *t = NULL, *lang = NULL;
       
   898 	char		*region = NULL, *encoding = NULL;
       
   899 
       
   900 	*return_list = NULL;
       
   901 
       
   902 	if (install_list == NULL || *install_list == NULL) {
       
   903 		om_set_error(OM_INVALID_LANG_LIST);
       
   904 		return;
       
   905 	}
       
   906 
       
   907 	(void) memset(trans, 0, sizeof (trans));
       
   908 	/*
       
   909 	 * For the installer application supported languages we only
       
   910 	 * want the non-UTF-8 codeset. Why? Because there is not full
       
   911 	 * locale support for UTF-8 in the miniroot.
       
   912 	 */
       
   913 	for (i = 0; i < lang_total && install_list[i] != NULL; i++) {
       
   914 		start = install_list[i];
       
   915 		lang = get_locale_component(&t, &start);
       
   916 
       
   917 		if (start && *t == COUNTRY_SEP)
       
   918 			region = get_locale_component(&t, &start);
       
   919 
       
   920 		if (start && *t == CODESET_SEP)
       
   921 			encoding = get_locale_component(&t, &start);
       
   922 
       
   923 		if (encoding != NULL) {
       
   924 			if (strcmp(encoding, UTF) == 0) {
       
   925 				free(encoding);
       
   926 				free(region);
       
   927 				free(lang);
       
   928 				encoding = NULL;
       
   929 				region = NULL;
       
   930 				lang = NULL;
       
   931 				continue;
       
   932 			}
       
   933 		}
       
   934 
       
   935 		if (strncmp(lang, "zh", 2) == 0) {
       
   936 			if (region != NULL && strcmp(region, "TW") == 0) {
       
   937 				om_errno = handle_chinese_language(region,
       
   938 				    &lang);
       
   939 				if (om_errno != OM_SUCCESS) {
       
   940 					goto error;
       
   941 				}
       
   942 			}
       
   943 		} else if (strcmp(lang, "C") == 0 ||
       
   944 		    strcmp(lang, "POSIX") == 0) {
       
   945 			free(lang);
       
   946 			lang = strdup("en");
       
   947 			is_default = B_TRUE;
       
   948 			if (lang == NULL) {
       
   949 				om_set_error(OM_NO_SPACE);
       
   950 				goto error;
       
   951 			}
       
   952 		}
       
   953 
       
   954 		if ((lp = get_lang_entry(lang, *return_list)) != NULL) {
       
   955 			continue;
       
   956 		} else {
       
   957 			ret = create_lang_entry(install_list[i],
       
   958 			    install_list[i], region, return_list, is_default);
       
   959 			if (!ret)
       
   960 				num_entries++;
       
   961 		}
       
   962 		free(lang);
       
   963 		free(region);
       
   964 		free(encoding);
       
   965 		lang = NULL;
       
   966 		region = NULL;
       
   967 		encoding = NULL;
       
   968 		is_default = B_FALSE;
       
   969 	}
       
   970 
       
   971 	/*
       
   972 	 * For the install application language specifications, which
       
   973 	 * are located at /usr/lib/install/data/lib/locale, we need
       
   974 	 * to ensure we have an up to date locale/lang name for
       
   975 	 * translation. The lcttab file in /usr/lib/locale provides
       
   976 	 * the correct mapping.
       
   977 	 */
       
   978 	lp = *return_list;
       
   979 	(void) snprintf(path, sizeof (path), "%s/lcttab", nlspath);
       
   980 	if ((fp = fopen(path, "r"))) {
       
   981 		for (i = 0; lp != NULL; lp = lp->next) {
       
   982 			locp = lp->locale_info;
       
   983 			rewind(fp);
       
   984 			while (fgets(linebuf, 128, fp)) {
       
   985 				if (strlen(linebuf) == 0 ||
       
   986 				    linebuf[0] == '#') {
       
   987 					continue;
       
   988 				}
       
   989 				/* Search for whitespace */
       
   990 				for (c = linebuf; *c && !isspace(*c); c++)
       
   991 					;
       
   992 
       
   993 				if (*c != '\0') {
       
   994 					/* End of line - invalid input */
       
   995 					continue;
       
   996 				}
       
   997 				*c = '\0';
       
   998 				if (strcmp(linebuf, locp->locale_name) != 0) {
       
   999 					continue;
       
  1000 				}
       
  1001 
       
  1002 				/* Found the old name - get the new version */
       
  1003 				for (c++; *c && isspace(*c); c++)
       
  1004 					;
       
  1005 
       
  1006 				if (!*c) {
       
  1007 					continue;
       
  1008 				}
       
  1009 				for (c2 = c; *c2 && !isspace(*c2); c2++)
       
  1010 					;
       
  1011 
       
  1012 				*c2 = '\0';
       
  1013 				/*
       
  1014 				 * We are not interested in UTF-8
       
  1015 				 * codesets for now.
       
  1016 				 */
       
  1017 				if (strstr(c, UTF) != NULL)
       
  1018 					continue;
       
  1019 				(void) strcpy(trans, c);
       
  1020 				break;
       
  1021 			} /* end while */
       
  1022 
       
  1023 			/*
       
  1024 			 * We may have not found a match in the lcttab file.
       
  1025 			 * If not, copy the original locale data in and
       
  1026 			 * search for locale_map.
       
  1027 			 */
       
  1028 			if (trans[0] == '\0')
       
  1029 				(void) strcpy(trans, locp->locale_name);
       
  1030 
       
  1031 			locp = (locale_info_t *)malloc(sizeof (locale_info_t));
       
  1032 			if (locp == NULL) {
       
  1033 				om_set_error(OM_NO_SPACE);
       
  1034 				goto error;
       
  1035 			}
       
  1036 			(void) memset(locp, 0, sizeof (locale_info_t));
       
  1037 			locp->locale_name = strdup(trans);
       
  1038 			if (locp->locale_name == NULL) {
       
  1039 				om_free_locale_info(locp);
       
  1040 				om_set_error(OM_NO_SPACE);
       
  1041 				goto error;
       
  1042 			}
       
  1043 			(void) memset(trans, 0, sizeof (trans));
       
  1044 			/*
       
  1045 			 * free the original lang_info_t->locale_info
       
  1046 			 * data.
       
  1047 			 */
       
  1048 			om_free_locale_info(lp->locale_info);
       
  1049 			lp->locale_info = locp;
       
  1050 			lp->n_locales++;
       
  1051 		} /* end for */
       
  1052 	} /* end if */
       
  1053 
       
  1054 	/*
       
  1055 	 * Now, translate language names, in this order, in to native
       
  1056 	 * locale based on current locale data associated with this language.
       
  1057 	 */
       
  1058 	translate_lang_names(return_list);
       
  1059 	*ll_total = num_entries;
       
  1060 	(void) fclose(fp);
       
  1061 	return;
       
  1062 
       
  1063 error:
       
  1064 	(void) fclose(fp);
       
  1065 	om_free_lang_info(*return_list);
       
  1066 	*return_list = NULL;
       
  1067 	*ll_total = 0;
       
  1068 	free(lang);
       
  1069 	free(region);
       
  1070 	free(encoding);
       
  1071 	free(start);
       
  1072 }
       
  1073 
       
  1074 static void
       
  1075 build_ll_list(char **list, int lang_total, lang_info_t **return_list,
       
  1076     int *total)
       
  1077 {
       
  1078 	int		i;
       
  1079 	int		ret = 0;
       
  1080 	int		num_langs = 0;
       
  1081 	char		*lang = NULL, *encoding = NULL, *region = NULL;
       
  1082 	char		*locale = NULL;
       
  1083 	lang_info_t	*lp = NULL;
       
  1084 	char		*orig, *start = NULL;
       
  1085 	char		*t = NULL;
       
  1086 	boolean_t	is_default = B_FALSE;
       
  1087 
       
  1088 	*total = 0;
       
  1089 
       
  1090 	/*
       
  1091 	 * lang_list passed in is a sorted list of the data found in
       
  1092 	 * the locale directory. Take this sorted list,
       
  1093 	 * parse appropriately, and insert locale data for each language
       
  1094 	 * in to the return_list.
       
  1095 	 */
       
  1096 
       
  1097 	for (i = 0; i < lang_total; i++)  {
       
  1098 		orig = start = list[i];
       
  1099 		if (!is_valid_locale(list[i]))
       
  1100 			continue;
       
  1101 
       
  1102 		t = NULL;
       
  1103 		lang = get_locale_component(&t, &start);
       
  1104 
       
  1105 		/*
       
  1106 		 * If we found a country or codeset sep then we found a
       
  1107 		 * locale.  The lang value is the language part of
       
  1108 		 * the lang/locale pair. What was in the original list
       
  1109 		 * is the locale.
       
  1110 		 */
       
  1111 		if (start && *t == COUNTRY_SEP) {
       
  1112 			region = get_locale_component(&t, &start);
       
  1113 		}
       
  1114 
       
  1115 		if (start && *t == CODESET_SEP) {
       
  1116 			encoding = get_locale_component(&t, &start);
       
  1117 		}
       
  1118 
       
  1119 		if (strncmp(lang, "zh", 2) == 0) {
       
  1120 			/*
       
  1121 			 * If there is a region with the Chinese lang,
       
  1122 			 * we need to ensure that it is not its own language.
       
  1123 			 * Chinese specifications for language include
       
  1124 			 * the region, such as zh_HK and zh_TW.
       
  1125 			 * If no region is found, then lang is simply lang
       
  1126 			 * from above.
       
  1127 			 */
       
  1128 			if (region) {
       
  1129 				om_errno = handle_chinese_language(region,
       
  1130 				    &lang);
       
  1131 				if (om_errno != OM_SUCCESS) {
       
  1132 					goto error;
       
  1133 				}
       
  1134 			} else {
       
  1135 				/*
       
  1136 				 * We need to account for Simplified Chinese,
       
  1137 				 * EUC in the locale list. Its locale name
       
  1138 				 * does not include a region.
       
  1139 				 */
       
  1140 				locale = strdup(lang);
       
  1141 				if (locale == NULL) {
       
  1142 					om_set_error(OM_NO_SPACE);
       
  1143 					goto error;
       
  1144 				}
       
  1145 			}
       
  1146 		} else if (strcmp(lang, "C") == 0 ||
       
  1147 		    strcmp(lang, "POSIX") == 0) {
       
  1148 			free(lang);
       
  1149 			lang = strdup("en");
       
  1150 			if (lang == NULL) {
       
  1151 				om_set_error(OM_NO_SPACE);
       
  1152 				goto error;
       
  1153 			}
       
  1154 			locale = strdup(lang);
       
  1155 			if (locale == NULL) {
       
  1156 				om_set_error(OM_NO_SPACE);
       
  1157 				goto error;
       
  1158 			}
       
  1159 		}
       
  1160 		/*
       
  1161 		 * Locale is a combination of  lang, country and codeset.
       
  1162 		 */
       
  1163 		if (encoding != NULL) {
       
  1164 			locale = strdup(orig);
       
  1165 			if (locale == NULL) {
       
  1166 				om_set_error(OM_NO_SPACE);
       
  1167 				goto error;
       
  1168 			}
       
  1169 		}
       
  1170 
       
  1171 		/*
       
  1172 		 * If we don't have the locale value, we haven't found
       
  1173 		 * anything we are interested in, so skip.
       
  1174 		 */
       
  1175 		if (locale != NULL)  {
       
  1176 			is_default = is_locale_in_installer_lang(locale);
       
  1177 			if ((lp = get_lang_entry(lang, *return_list)) != NULL) {
       
  1178 				add_locale_entry_to_lang(lp, locale, region,
       
  1179 				    is_default);
       
  1180 			} else {
       
  1181 				ret = create_lang_entry(lang, locale, region,
       
  1182 				    return_list, is_default);
       
  1183 				if (!ret) {
       
  1184 					num_langs++;
       
  1185 					om_debug_print(OM_DBGLVL_INFO,
       
  1186 					    "num_langs = %d\n", num_langs);
       
  1187 				}
       
  1188 			}
       
  1189 		}
       
  1190 		free(region);
       
  1191 		free(encoding);
       
  1192 		free(lang);
       
  1193 		free(locale);
       
  1194 		region = NULL;
       
  1195 		encoding = NULL;
       
  1196 		lang = NULL;
       
  1197 		locale = NULL;
       
  1198 	}
       
  1199 	*total = num_langs;
       
  1200 	return;
       
  1201 error:
       
  1202 	om_free_lang_info(*return_list);
       
  1203 	*return_list = NULL;
       
  1204 	free(region);
       
  1205 	free(encoding);
       
  1206 	free(lang);
       
  1207 	free(locale);
       
  1208 }
       
  1209 
       
  1210 /*
       
  1211  * build_language_list:
       
  1212  *
       
  1213  *	The idea is to scan the directories under "path" and
       
  1214  *	build the language list, char ** list, associated with
       
  1215  *	the "path".
       
  1216  */
       
  1217 static int
       
  1218 build_language_list(char *path, char **list, int *total)
       
  1219 {
       
  1220 	DIR		*locale_dir;
       
  1221 	struct dirent	*locale;		/* entries in locale_dir */
       
  1222 	int		i = 0;
       
  1223 
       
  1224 	/*
       
  1225 	 * Read in language data from the locale directory.
       
  1226 	 */
       
  1227 	(void) memset(list, 0, sizeof (*list));
       
  1228 	locale_dir = opendir(path);
       
  1229 	if (locale_dir == NULL) {
       
  1230 		if (errno == EACCES) {
       
  1231 			om_set_error(OM_PERMS);
       
  1232 		} else if (errno != EMFILE && errno != ENFILE) {
       
  1233 			om_set_error(OM_NO_LOCALE_DIR);
       
  1234 		} else {
       
  1235 			om_set_error(OM_TOO_MANY_FD);
       
  1236 		}
       
  1237 		goto error;
       
  1238 	}
       
  1239 
       
  1240 	while (locale = readdir(locale_dir)) {
       
  1241 		/*
       
  1242 		 * Exclude current and parent directory. Make sure
       
  1243 		 * we are not over our buffer limit.
       
  1244 		 */
       
  1245 		if (strcmp(locale->d_name, ".") == 0 ||
       
  1246 		    strcmp(locale->d_name, "..") == 0)
       
  1247 			continue;
       
  1248 
       
  1249 		list[i] = strdup(locale->d_name);
       
  1250 		if (list[i] == NULL) {
       
  1251 			om_set_error(OM_NO_SPACE);
       
  1252 			goto error;
       
  1253 		}
       
  1254 		i++;
       
  1255 	}
       
  1256 	*total = i;
       
  1257 	(void) closedir(locale_dir);
       
  1258 	return (OM_SUCCESS);
       
  1259 
       
  1260 error:
       
  1261 	om_free_lang_names(list);
       
  1262 	*list = NULL;
       
  1263 	(void) closedir(locale_dir);
       
  1264 	return (OM_FAILURE);
       
  1265 }
       
  1266 /*
       
  1267  * This function reads a locales locale_map file to get the settings
       
  1268  * that should be used for localization.
       
  1269  *
       
  1270  * Input: File *fp  File pointer to locale_map file
       
  1271  * Output: Each type of locale category value is returned.
       
  1272  */
       
  1273 int
       
  1274 read_locale_file(FILE *fp, char *lang, char *lc_collate, char *lc_ctype,
       
  1275 	char *lc_messages, char *lc_monetary, char *lc_numeric, char *lc_time)
       
  1276 {
       
  1277 	int status = 0;
       
  1278 	char line[BUFSIZ];
       
  1279 
       
  1280 	(void) strcpy(lc_collate, "C");
       
  1281 	(void) strcpy(lc_ctype, "C");
       
  1282 	(void) strcpy(lc_messages, "C");
       
  1283 	(void) strcpy(lc_monetary, "C");
       
  1284 	(void) strcpy(lc_numeric, "C");
       
  1285 	(void) strcpy(lc_time, "C");
       
  1286 
       
  1287 	while (fgets(line, BUFSIZ, fp) != NULL) {
       
  1288 		/*
       
  1289 		 * Remove the trailing newline, and strip any comments that
       
  1290 		 * may appear on the read line.
       
  1291 		 */
       
  1292 		line[strlen(line) - 1] = '\0';
       
  1293 		(void) strip_comment(line);
       
  1294 
       
  1295 		if (strncmp(STR_LANG, line, LEN_LANG) == 0) {
       
  1296 			(void) strcpy(lang, line + LEN_LANG);
       
  1297 			status = 1;
       
  1298 		} else if (strncmp(STR_LC_COLLATE, line, LEN_LC_COLLATE) == 0) {
       
  1299 			(void) strcpy(lc_collate, line + LEN_LC_COLLATE);
       
  1300 			status = 2;
       
  1301 		} else if (strncmp(STR_LC_CTYPE, line, LEN_LC_CTYPE) == 0) {
       
  1302 			(void) strcpy(lc_ctype, line + LEN_LC_CTYPE);
       
  1303 			status = 2;
       
  1304 		} else if (strncmp(STR_LC_MESSAGES, line, LEN_LC_MESSAGES)
       
  1305 		    == 0) {
       
  1306 			(void) strcpy(lc_messages, line + LEN_LC_MESSAGES);
       
  1307 			status = 2;
       
  1308 		} else if (strncmp(STR_LC_MONETARY, line, LEN_LC_MONETARY)
       
  1309 		    == 0) {
       
  1310 			(void) strcpy(lc_monetary, line + LEN_LC_MONETARY);
       
  1311 			status = 2;
       
  1312 		} else if (strncmp(STR_LC_NUMERIC, line, LEN_LC_NUMERIC) == 0) {
       
  1313 			(void) strcpy(lc_numeric, line + LEN_LC_NUMERIC);
       
  1314 			status = 2;
       
  1315 		} else if (strncmp(STR_LC_TIME, line, LEN_LC_TIME) == 0) {
       
  1316 			(void) strcpy(lc_time, line + LEN_LC_TIME);
       
  1317 			status = 2;
       
  1318 		}
       
  1319 	}
       
  1320 
       
  1321 	if (status == 1) {
       
  1322 		/*
       
  1323 		 * There's a LANG, but nothing else, so populate all of the
       
  1324 		 * fields with the value put in LANG
       
  1325 		 */
       
  1326 		(void) strcpy(lc_collate, lang);
       
  1327 		(void) strcpy(lc_ctype, lang);
       
  1328 		(void) strcpy(lc_messages, lang);
       
  1329 		(void) strcpy(lc_monetary, lang);
       
  1330 		(void) strcpy(lc_numeric, lang);
       
  1331 		(void) strcpy(lc_time, lang);
       
  1332 	}
       
  1333 	return (status);
       
  1334 }
       
  1335 
       
  1336 /*
       
  1337  * Function:	strip_comment
       
  1338  * Description:	Given a string of the form 'foo # comment', strip the comment
       
  1339  *		text, the comment marker, and the whitespace (if any) preceding
       
  1340  *		it.  This modification is done in-place on the passed in string.
       
  1341  * Scope:	private
       
  1342  * Arguments:	buf	- [RO, *RW] (char *)
       
  1343  *			  The buffer from which the comment is to be stripped.
       
  1344  * Returns:	char *	- buf, the pointer passed in
       
  1345  */
       
  1346 static char *
       
  1347 strip_comment(char *buf)
       
  1348 {
       
  1349 	char *comchr;
       
  1350 
       
  1351 	if (buf == NULL || (comchr = strchr(buf, '#')) == NULL)
       
  1352 		return (buf);
       
  1353 
       
  1354 	for (; comchr != buf && isspace(*(comchr - 1)); comchr--)
       
  1355 		;
       
  1356 	*comchr = '\0';
       
  1357 	return (buf);
       
  1358 }
       
  1359 static void
       
  1360 set_lang(char *locale)
       
  1361 {
       
  1362 	static char	tmpstr[MAX_LOCALE + 6];
       
  1363 
       
  1364 	(void) setlocale(LC_ALL, locale);
       
  1365 	(void) snprintf(tmpstr, sizeof (tmpstr), "LANG=%s", locale);
       
  1366 	(void) putenv(tmpstr);
       
  1367 }
       
  1368 
       
  1369 static void
       
  1370 set_lc(char *lc_collate, char *lc_ctype, char *lc_messages, char *lc_monetary,
       
  1371 	char *lc_numeric, char *lc_time)
       
  1372 {
       
  1373 
       
  1374 	/*
       
  1375 	 * The longest addition to a locale value is LC_MESSAGES=. This
       
  1376 	 * plus the NULL value is 14 chars. Added 15 for padding as
       
  1377 	 * a result.
       
  1378 	 */
       
  1379 	static char	tmpstr1[MAX_LOCALE + 15];
       
  1380 	static char	tmpstr2[MAX_LOCALE + 15];
       
  1381 	static char	tmpstr3[MAX_LOCALE + 15];
       
  1382 	static char	tmpstr4[MAX_LOCALE + 15];
       
  1383 	static char	tmpstr5[MAX_LOCALE + 15];
       
  1384 	static char	tmpstr6[MAX_LOCALE + 15];
       
  1385 	char		*loc = NULL;
       
  1386 
       
  1387 	loc = setlocale(LC_COLLATE, lc_collate);
       
  1388 	if (loc)
       
  1389 		om_debug_print(OM_DBGLVL_INFO, "lc_collate set to %s\n", loc);
       
  1390 	else
       
  1391 		om_debug_print(OM_DBGLVL_WARN,
       
  1392 		    "Could not set lc_collate value\n");
       
  1393 
       
  1394 	(void) snprintf(tmpstr1, sizeof (tmpstr1), "LC_COLLATE=%s", lc_collate);
       
  1395 	(void) putenv(tmpstr1);
       
  1396 
       
  1397 	loc = setlocale(LC_CTYPE, lc_ctype);
       
  1398 	if (loc)
       
  1399 		om_debug_print(OM_DBGLVL_INFO,
       
  1400 		    "lc_ctype set to %s\n", loc);
       
  1401 	else
       
  1402 		om_debug_print(OM_DBGLVL_WARN,
       
  1403 		    "Could not set lc_ctype value\n");
       
  1404 	(void) snprintf(tmpstr2, sizeof (tmpstr2), "LC_CTYPE=%s", lc_ctype);
       
  1405 	(void) putenv(tmpstr2);
       
  1406 
       
  1407 	loc = setlocale(LC_MESSAGES, lc_messages);
       
  1408 	if (loc)
       
  1409 		om_debug_print(OM_DBGLVL_INFO,
       
  1410 		    "lc_messages set to %s\n", loc);
       
  1411 	else
       
  1412 		om_debug_print(OM_DBGLVL_WARN,
       
  1413 		    "Could not set lc_messages value\n");
       
  1414 	(void) snprintf(tmpstr3, sizeof (tmpstr3),
       
  1415 	    "LC_MESSAGES=%s", lc_messages);
       
  1416 	(void) putenv(tmpstr3);
       
  1417 
       
  1418 	loc =  setlocale(LC_MONETARY, lc_monetary);
       
  1419 	if (loc)
       
  1420 		om_debug_print(OM_DBGLVL_INFO,
       
  1421 		    "lc_monetary set to %s\n", loc);
       
  1422 	else
       
  1423 		om_debug_print(OM_DBGLVL_WARN,
       
  1424 		    "Could not set lc_monetary value\n");
       
  1425 	(void) snprintf(tmpstr4, sizeof (tmpstr4),
       
  1426 	    "LC_MONETARY=%s", lc_monetary);
       
  1427 	(void) putenv(tmpstr4);
       
  1428 
       
  1429 	loc = setlocale(LC_NUMERIC, lc_numeric);
       
  1430 	if (loc)
       
  1431 		om_debug_print(OM_DBGLVL_INFO,
       
  1432 		    "lc_numeric set to %s\n", loc);
       
  1433 	else
       
  1434 		om_debug_print(OM_DBGLVL_WARN,
       
  1435 		    "Could not set lc_numeric value\n");
       
  1436 	(void) snprintf(tmpstr5, sizeof (tmpstr5), "LC_NUMERIC=%s", lc_numeric);
       
  1437 	(void) putenv(tmpstr5);
       
  1438 
       
  1439 	loc = setlocale(LC_TIME, lc_time);
       
  1440 	if (loc)
       
  1441 		om_debug_print(OM_DBGLVL_INFO,
       
  1442 		    "lc_time set to %s\n", loc);
       
  1443 	else
       
  1444 		om_debug_print(OM_DBGLVL_WARN,
       
  1445 		    "Could not set lc_time value\n");
       
  1446 	(void) snprintf(tmpstr6, sizeof (tmpstr6), "LC_TIME=%s", lc_time);
       
  1447 	(void) putenv(tmpstr6);
       
  1448 }
       
  1449 
       
  1450 /*
       
  1451  * Name:	get_locale_description
       
  1452  * Description:	Read the locale_description file for a given locale, returning
       
  1453  *		a pointer to a buffer containing the contents of that
       
  1454  *		file.
       
  1455  * Scope:	private
       
  1456  * Arguments:	locale	- [RO, *RO] (char *)
       
  1457  *			  The locale whose locale_description is to be read
       
  1458  * Returns:	char *	- The first line of the locale_description
       
  1459  */
       
  1460 static char *
       
  1461 get_locale_description(char *lang, char *region)
       
  1462 {
       
  1463 	char	*user_desc;
       
  1464 
       
  1465 	/*
       
  1466 	 * Chinese and Korean are handled differently. This is due to
       
  1467 	 * the locale description for each of these being different than
       
  1468 	 * the standard.
       
  1469 	 */
       
  1470 
       
  1471 	if (region == NULL) {
       
  1472 		if (strcmp(lang, dgettext(TEXT_DOMAIN, TRADITIONAL_CHINESE))
       
  1473 		    == 0 ||
       
  1474 		    strcmp(lang, dgettext(TEXT_DOMAIN, SIMPLIFIED_CHINESE))
       
  1475 		    == 0) {
       
  1476 			region = strdup("zh");
       
  1477 		} else if (strcmp(lang, dgettext(TEXT_DOMAIN, "Korean")) == 0) {
       
  1478 			region = strdup("ko");
       
  1479 		}
       
  1480 	}
       
  1481 	user_desc = translate_description(lang, region);
       
  1482 	return (user_desc);
       
  1483 }
       
  1484 
       
  1485 static char *
       
  1486 translate_description(char *lang, char *region)
       
  1487 {
       
  1488 	char 		*trans_desc = NULL;
       
  1489 	int		len = 0, i;
       
  1490 	int		szcountry = sizeof (orchestrator_country_list) /
       
  1491 	    sizeof (orchestrator_country_list[0]);
       
  1492 
       
  1493 	char		*tmp_ctrystring = NULL;
       
  1494 
       
  1495 	if (lang == NULL || region == NULL) {
       
  1496 		return (NULL);
       
  1497 	}
       
  1498 
       
  1499 	for (i = 0; i < szcountry; i++) {
       
  1500 		/*
       
  1501 		 * Translate the country code for this locale.
       
  1502 		 */
       
  1503 		if (strncasecmp(region,
       
  1504 		    orchestrator_country_list[i].country_code, 2) == 0) {
       
  1505 			tmp_ctrystring =
       
  1506 			    dgettext(TEXT_DOMAIN,
       
  1507 			    orchestrator_country_list[i].country_name);
       
  1508 			break;
       
  1509 		}
       
  1510 	}
       
  1511 	if (tmp_ctrystring) {
       
  1512 		len = strlen(lang) + strlen(tmp_ctrystring) + 4;
       
  1513 		trans_desc = (char *)malloc(len);
       
  1514 		if (trans_desc == NULL)
       
  1515 			return (NULL);
       
  1516 		(void) snprintf(trans_desc, len, "%s (%s)",
       
  1517 		    lang, tmp_ctrystring);
       
  1518 	}
       
  1519 	return (trans_desc);
       
  1520 }
       
  1521 
       
  1522 static char **
       
  1523 get_actual_languages(char **list, int *total)
       
  1524 {
       
  1525 	char	**lp;
       
  1526 	char	**lang_listp = NULL;
       
  1527 	size_t	sz;
       
  1528 	int	ret = 0;
       
  1529 	int	i, j, k = 0;
       
  1530 
       
  1531 
       
  1532 	*total = 0;
       
  1533 
       
  1534 	if (list == NULL || *list == NULL)
       
  1535 		return (NULL);
       
  1536 
       
  1537 	sz = sizeof (orchestrator_lang_list)/sizeof (orchestrator_lang_list[0]);
       
  1538 
       
  1539 	lp = list;
       
  1540 	for (i = 0; lp[i] != '\0'; i++) {
       
  1541 		for (j = 0; j < sz; j++) {
       
  1542 			if (strncmp(lp[i],
       
  1543 			    (char *)orchestrator_lang_list[j].lang_code,
       
  1544 			    2) == 0) {
       
  1545 				ret = add_lang_to_list(&lang_listp,
       
  1546 				    lp[i], &k, j);
       
  1547 				if (ret) {
       
  1548 					om_free_lang_names(lang_listp);
       
  1549 					return (NULL);
       
  1550 				}
       
  1551 				break;
       
  1552 			}
       
  1553 		}
       
  1554 	}
       
  1555 	/*
       
  1556 	 * No lang translation found. Return existing list.
       
  1557 	 */
       
  1558 	if (j == sz) {
       
  1559 		return (lang_listp);
       
  1560 	}
       
  1561 	*total = k;
       
  1562 	om_set_error(OM_SUCCESS);
       
  1563 	return (lang_listp);
       
  1564 }
       
  1565 
       
  1566 static int
       
  1567 add_lang_to_list(char ***list, char *locale, int *k, int j)
       
  1568 {
       
  1569 	int	i;
       
  1570 	char	**lpp = *list;
       
  1571 	char	**tmp_list;
       
  1572 	char	*tmp = NULL;
       
  1573 	char	*code;
       
  1574 
       
  1575 	tmp_list = *list;
       
  1576 
       
  1577 	if (strncmp(locale, "zh", 2) == 0) {
       
  1578 		tmp = strdup(dgettext(TEXT_DOMAIN,
       
  1579 		    substitute_chinese_language(locale, &code)));
       
  1580 	} else if (strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0 ||
       
  1581 	    strcmp(locale, "C/POSIX") == 0) {
       
  1582 		tmp = strdup(dgettext(TEXT_DOMAIN, "English"));
       
  1583 	} else {
       
  1584 		tmp = strdup(dgettext(TEXT_DOMAIN,
       
  1585 		    orchestrator_lang_list[j].lang_name));
       
  1586 	}
       
  1587 
       
  1588 	if (tmp == NULL) {
       
  1589 		om_set_error(OM_NO_SPACE);
       
  1590 		return (OM_FAILURE);
       
  1591 	}
       
  1592 
       
  1593 	if (tmp_list != NULL) {
       
  1594 		/*
       
  1595 		 * Search for existence of this language in the list already
       
  1596 		 */
       
  1597 		for (i = 0; tmp_list[i] != NULL && tmp_list[i] != '\0' &&
       
  1598 		    i < *k; i++) {
       
  1599 			if (strcmp(tmp, tmp_list[i]) == 0) {
       
  1600 				free(tmp);
       
  1601 				return (OM_SUCCESS);
       
  1602 			}
       
  1603 		}
       
  1604 	}
       
  1605 	tmp_list = (char **)realloc(*list, ((*k) + 1) * sizeof (char *));
       
  1606 	if (tmp_list == NULL) {
       
  1607 		free(tmp);
       
  1608 		om_set_error(OM_NO_SPACE);
       
  1609 		return (OM_FAILURE);
       
  1610 	}
       
  1611 	lpp = *list = tmp_list;
       
  1612 	lpp[*k] = tmp;
       
  1613 	(*k)++;
       
  1614 	return (OM_SUCCESS);
       
  1615 }
       
  1616 
       
  1617 static boolean_t
       
  1618 is_valid_locale(char *locale)
       
  1619 {
       
  1620 
       
  1621 	char	path[MAXPATHLEN];
       
  1622 	struct	stat stat_buf;
       
  1623 
       
  1624 	if (locale == NULL)
       
  1625 		return (B_FALSE);
       
  1626 
       
  1627 	if (strstr(locale, UTF) == NULL)
       
  1628 		return (B_FALSE);
       
  1629 
       
  1630 	(void) snprintf(path, sizeof (path), "%s/%s/locale_map",
       
  1631 	    NLS_PATH, locale);
       
  1632 	if ((stat(path, &stat_buf) == 0) &&
       
  1633 	    ((stat_buf.st_mode & S_IFMT) == S_IFREG)) {
       
  1634 		return (B_TRUE);
       
  1635 	}
       
  1636 	return (B_FALSE);
       
  1637 }
       
  1638 static char *
       
  1639 substitute_C_POSIX_language(char **code)
       
  1640 {
       
  1641 	char	*lang = NULL;
       
  1642 
       
  1643 	/*
       
  1644 	 * locale is C and or POSIX. Set to English, set code
       
  1645 	 * to 'en'.
       
  1646 	 */
       
  1647 	lang = strdup(dgettext(TEXT_DOMAIN, "English"));
       
  1648 	if (lang == NULL) {
       
  1649 		om_set_error(OM_NO_SPACE);
       
  1650 		*code = NULL;
       
  1651 		return (lang);
       
  1652 	}
       
  1653 	*code = strdup("en");
       
  1654 	if (*code == NULL) {
       
  1655 		free(lang);
       
  1656 		lang = NULL;
       
  1657 		om_set_error(OM_NO_SPACE);
       
  1658 	}
       
  1659 	return (lang);
       
  1660 }
       
  1661 
       
  1662 static char *
       
  1663 substitute_chinese_language(char *locale, char **code)
       
  1664 {
       
  1665 	int 		i;
       
  1666 	char		*sub = NULL;
       
  1667 
       
  1668 	*code = NULL;
       
  1669 
       
  1670 	for (i = 0; chinese_values[i].lang; i++) {
       
  1671 		if (strcmp(locale, chinese_values[i].lang) == 0) {
       
  1672 			sub = strdup(chinese_values[i].lang_name);
       
  1673 			*code = strdup(chinese_values[i].lang_code);
       
  1674 			if (sub == NULL || *code == NULL) {
       
  1675 				free(sub);
       
  1676 				om_set_error(OM_NO_SPACE);
       
  1677 				return (NULL);
       
  1678 			} else {
       
  1679 				return (sub);
       
  1680 			}
       
  1681 		}
       
  1682 	}
       
  1683 	return (sub);
       
  1684 }
       
  1685 
       
  1686 static void
       
  1687 sort_lang_list(char **unsorted_list, int total)
       
  1688 {
       
  1689 	qsort((char **)unsorted_list, total, sizeof (char *), list_cmp);
       
  1690 }
       
  1691 
       
  1692 static int
       
  1693 handle_chinese_language(char *region, char **lang)
       
  1694 {
       
  1695 	int	len;
       
  1696 	char	*chinese_lang;
       
  1697 
       
  1698 
       
  1699 	len = strlen(*lang) + strlen(region) + 3;
       
  1700 	chinese_lang = (char *)malloc(len);
       
  1701 	/*
       
  1702 	 * If we cannot allocate new language data, return error, but
       
  1703 	 * don't modify language value. Allow caller to determine what
       
  1704 	 * to do.
       
  1705 	 */
       
  1706 	if (chinese_lang == NULL) {
       
  1707 		om_set_error(OM_NO_SPACE);
       
  1708 		return (OM_FAILURE);
       
  1709 	}
       
  1710 	(void) snprintf(chinese_lang, len, "%s%s%s", *lang, "_", region);
       
  1711 	free(*lang);
       
  1712 	*lang = chinese_lang;
       
  1713 	return (OM_SUCCESS);
       
  1714 }
       
  1715 static int
       
  1716 list_cmp(const void *p1, const void *p2)
       
  1717 {
       
  1718 	return (strcmp(*(char **)p1, *(char **)p2));
       
  1719 
       
  1720 }
       
  1721 /*
       
  1722  * This function gets each of the locale components. It does so
       
  1723  * by looking for each component of a locale, as noted above as defines.
       
  1724  * It returns each segment in t, or NULL if no additional component is found.
       
  1725  */
       
  1726 static char *
       
  1727 get_locale_component(char **t, char **start)
       
  1728 {
       
  1729 	char	*result = NULL;
       
  1730 
       
  1731 	end_of_comp(t, start);
       
  1732 	result = copy_up_to(*start, *t);
       
  1733 	*start = (**t != '\0') ? *t + 1: NULL;
       
  1734 	return (result);
       
  1735 }
       
  1736 
       
  1737 /*
       
  1738  * This function looks for each component of the locale string passed in
       
  1739  * in the 'start' parameter. If it finds one it returns a pointer to that
       
  1740  * component. Or NULL if not found.
       
  1741  */
       
  1742 static void
       
  1743 end_of_comp(char **t, char **start)
       
  1744 {
       
  1745 	(((*t) = strchr((*start), COUNTRY_SEP)) != NULL) ||
       
  1746 	    (((*t) = strchr((*start), CODESET_SEP)) != NULL) ||
       
  1747 	/*LINTED*/
       
  1748 	    (((*t) = strchr((*start), '\0')) != NULL);
       
  1749 }
       
  1750 
       
  1751 static char *
       
  1752 copy_up_to(char *start, char *end)
       
  1753 {
       
  1754 	/*
       
  1755 	 * XXX look at this.
       
  1756 	 */
       
  1757 
       
  1758 	ptrdiff_t	diff;
       
  1759 	char		*sub = NULL;
       
  1760 
       
  1761 	if (end == NULL) {
       
  1762 		diff = strlen(start);
       
  1763 	} else {
       
  1764 		/*LINTED*/
       
  1765 		diff = end - start;
       
  1766 	}
       
  1767 	sub = (char *)malloc(diff + 1);
       
  1768 	(void) memset(sub, 0, diff + 1);
       
  1769 	(void) strlcpy(sub, start, (diff + 1));
       
  1770 	return (sub);
       
  1771 }
       
  1772 
       
  1773 static boolean_t
       
  1774 is_locale_in_installer_lang(char *locale_name)
       
  1775 {
       
  1776 	if (app_locale == NULL) {
       
  1777 		app_locale = strdup(setlocale(LC_MESSAGES, NULL));
       
  1778 	}
       
  1779 
       
  1780 	if (app_locale != NULL) {
       
  1781 		if (strcmp(locale_name, app_locale) == 0) {
       
  1782 			/* locale name is same */
       
  1783 			return (B_TRUE);
       
  1784 		} else if (strncmp(locale_name, app_locale, 2) == 0) {
       
  1785 			/* language part is same */
       
  1786 			if ((strncmp(locale_name, "zh_TW", 5) == 0) ||
       
  1787 			    (strncmp(locale_name, "zh_HK", 5) == 0)) {
       
  1788 				/* traditional Chinese */
       
  1789 				if ((strncmp(app_locale, "zh_TW", 5) == 0) ||
       
  1790 				    (strncmp(app_locale, "zh_HK", 5) == 0)) {
       
  1791 					return (B_TRUE);
       
  1792 				}
       
  1793 			} else if (strncmp(locale_name, "zh", 2) == 0) {
       
  1794 				/* simplified Chinese */
       
  1795 				if ((strncmp(app_locale, "zh_TW", 5) != 0) &&
       
  1796 				    (strncmp(app_locale, "zh_HK", 5) != 0)) {
       
  1797 					return (B_TRUE);
       
  1798 				}
       
  1799 			} else {
       
  1800 				/* others */
       
  1801 				return (B_TRUE);
       
  1802 			}
       
  1803 		} else if (strncmp(locale_name, "en", 2) == 0) {
       
  1804 			/* English */
       
  1805 			if (strcmp(app_locale, "C") == 0) {
       
  1806 				return (B_TRUE);
       
  1807 			}
       
  1808 		}
       
  1809 	}
       
  1810 
       
  1811 	return (B_FALSE);
       
  1812 }
       
  1813 void
       
  1814 om_save_locale(char *locale, boolean_t install_only)
       
  1815 {
       
  1816 	FILE 	*fp, *tfp;
       
  1817 	char	line[BUFSIZ];
       
  1818 	char	tfile[80];
       
  1819 	char	target[MAXPATHLEN];
       
  1820 
       
  1821 	/*
       
  1822 	 * If this is only setting the installation app locale we don't
       
  1823 	 * want to modify the users /etc/default/init file just yet. That
       
  1824 	 * will happen later.
       
  1825 	 */
       
  1826 
       
  1827 	if (install_only) {
       
  1828 		update_env(locale);
       
  1829 	}
       
  1830 
       
  1831 	(void) sprintf(tfile, "/tmp/orchlocale%ld", getpid());
       
  1832 	(void) snprintf(target, sizeof (target), "%s%s", get_rootdir(),
       
  1833 	    INIT_FILE);
       
  1834 
       
  1835 	if ((tfp = fopen(tfile, "w")) == NULL)
       
  1836 		return;
       
  1837 
       
  1838 	if ((fp = fopen(target, "r")) != NULL) {
       
  1839 		while (fgets(line, BUFSIZ, fp) != NULL) {
       
  1840 			if (strncmp("LANG=", line, 5) == 0)
       
  1841 				continue;
       
  1842 			if (strncmp("LC_", line, 3) == 0)
       
  1843 				continue;
       
  1844 			if (fputs(line, tfp) == EOF) {
       
  1845 				(void) fclose(fp);
       
  1846 				(void) fclose(tfp);
       
  1847 				return;
       
  1848 			}
       
  1849 		}
       
  1850 	}
       
  1851 	(void) fclose(fp);
       
  1852 	update_init(tfp, locale);
       
  1853 	(void) fclose(tfp);
       
  1854 
       
  1855 	if ((fp = fopen(target, "w")) == NULL)
       
  1856 		return;
       
  1857 
       
  1858 	if ((tfp = fopen(tfile, "r")) == NULL) {
       
  1859 		(void) fclose(fp);
       
  1860 		return;
       
  1861 	}
       
  1862 
       
  1863 	while (fgets(line, BUFSIZ, tfp) != NULL)
       
  1864 		if (fputs(line, fp) == EOF)
       
  1865 			break;
       
  1866 	(void) fclose(fp);
       
  1867 	(void) fclose(tfp);
       
  1868 }
       
  1869 
       
  1870 static void
       
  1871 update_env(char *locale)
       
  1872 {
       
  1873 	char path[MAXPATHLEN];
       
  1874 	char lc_collate[MAX_LOCALE];
       
  1875 	char lc_ctype[MAX_LOCALE];
       
  1876 	char lc_messages[MAX_LOCALE];
       
  1877 	char lc_monetary[MAX_LOCALE];
       
  1878 	char lc_numeric[MAX_LOCALE];
       
  1879 	char lc_time[MAX_LOCALE];
       
  1880 	char lang[MAX_LOCALE];
       
  1881 	FILE *mfp;
       
  1882 	int rc;
       
  1883 
       
  1884 	(void) snprintf(path, sizeof (path), "%s/%s/locale_map",
       
  1885 	    NLS_PATH, locale);
       
  1886 	if ((mfp = fopen(path, "r")) == NULL) {
       
  1887 		set_lang(locale);
       
  1888 	} else {
       
  1889 		rc = read_locale_file(mfp, lang, lc_collate, lc_ctype,
       
  1890 		    lc_messages, lc_monetary, lc_numeric, lc_time);
       
  1891 		(void) fclose(mfp);
       
  1892 
       
  1893 		if (rc == 1) {
       
  1894 			set_lang(lc_messages);
       
  1895 		} else {
       
  1896 			set_lc(lc_collate, lc_ctype, lc_messages, lc_monetary,
       
  1897 			    lc_numeric, lc_time);
       
  1898 		}
       
  1899 	}
       
  1900 }
       
  1901 
       
  1902 static void
       
  1903 update_init(FILE *fp, char *locale)
       
  1904 {
       
  1905 	char path[MAXPATHLEN];
       
  1906 	char lc_collate[MAX_LOCALE];
       
  1907 	char lc_ctype[MAX_LOCALE];
       
  1908 	char lc_messages[MAX_LOCALE];
       
  1909 	char lc_monetary[MAX_LOCALE];
       
  1910 	char lc_numeric[MAX_LOCALE];
       
  1911 	char lc_time[MAX_LOCALE];
       
  1912 	char lang[MAX_LOCALE];
       
  1913 	FILE *mfp;
       
  1914 	int rc;
       
  1915 
       
  1916 	(void) snprintf(path, sizeof (path), "%s/%s/locale_map",
       
  1917 	    NLS_PATH, locale);
       
  1918 	if ((mfp = fopen(path, "r")) == NULL) {
       
  1919 		if (strcmp(locale, "C") != 0) {
       
  1920 			(void) fprintf(fp, "LANG=%s\n", locale);
       
  1921 		}
       
  1922 		set_lang(locale);
       
  1923 	} else {
       
  1924 		rc = read_locale_file(mfp, lang, lc_collate, lc_ctype,
       
  1925 		    lc_messages, lc_monetary, lc_numeric, lc_time);
       
  1926 		(void) fclose(mfp);
       
  1927 
       
  1928 		if (rc == 1) {
       
  1929 			(void) fprintf(fp, "LANG=%s\n", lc_messages);
       
  1930 			set_lang(lc_messages);
       
  1931 		} else {
       
  1932 			(void) fprintf(fp, "LC_COLLATE=%s\n", lc_collate);
       
  1933 			(void) fprintf(fp, "LC_CTYPE=%s\n", lc_ctype);
       
  1934 			(void) fprintf(fp, "LC_MESSAGES=%s\n", lc_messages);
       
  1935 			(void) fprintf(fp, "LC_MONETARY=%s\n", lc_monetary);
       
  1936 			(void) fprintf(fp, "LC_NUMERIC=%s\n", lc_numeric);
       
  1937 			(void) fprintf(fp, "LC_TIME=%s\n", lc_time);
       
  1938 		}
       
  1939 
       
  1940 	}
       
  1941 }
       
  1942 
       
  1943 static void
       
  1944 translate_lang_names(lang_info_t **list)
       
  1945 {
       
  1946 
       
  1947 	char		trans[512];
       
  1948 	lang_info_t	*langp;
       
  1949 
       
  1950 	/*
       
  1951 	 * Set locale to en_US.UTF-8. It doesn't really matter
       
  1952 	 * what it is set to expect it cannot be C. dgettext does
       
  1953 	 * not pick up the translated strings if the current locale
       
  1954 	 * is C.
       
  1955 	 */
       
  1956 	set_lang("en_US.UTF-8");
       
  1957 	for (langp = *list; langp != NULL; langp = langp->next) {
       
  1958 		if (langp->lang_name != NULL) {
       
  1959 			(void) strcpy(trans,
       
  1960 			    dgettext("SUNW_INSTALL_LANG",
       
  1961 			    langp->lang_name));
       
  1962 			/*
       
  1963 			 * Free original lang name.
       
  1964 			 */
       
  1965 			free(langp->lang_name);
       
  1966 			langp->lang_name = strdup(trans);
       
  1967 			if (langp->lang_name == NULL) {
       
  1968 				/*
       
  1969 				 * Log a message. leave the other
       
  1970 				 * lang names untranslated.
       
  1971 				 * Otherwise, would have to free
       
  1972 				 * full list and provide
       
  1973 				 * the user with nothing.
       
  1974 				 */
       
  1975 				om_debug_print(OM_DBGLVL_ERR,
       
  1976 				    "Couldn't allocate memory"
       
  1977 				    " for translated lang name\n");
       
  1978 				return;
       
  1979 			}
       
  1980 		}
       
  1981 	}
       
  1982 }