diff --git a/locale/programs/localedef.c b/locale/programs/localedef.c
index 06fca12..44f15e4 100644
--- a/locale/programs/localedef.c
+++ b/locale/programs/localedef.c
@@ -65,6 +65,9 @@ static int force_output;
 /* Prefix for output files.  */
 const char *output_prefix;
 
+/* Locale directory to use for output.  */
+const char *output_localedir;
+
 /* Name of the character map file.  */
 static const char *charmap_file;
 
@@ -74,6 +77,9 @@ static const char *input_file;
 /* Name of the repertoire map file.  */
 const char *repertoire_global;
 
+/* Location of the locale-archive file.  */
+const char *archive_file;
+
 /* Name of the locale.alias file.  */
 const char *alias_file;
 
@@ -107,11 +113,12 @@ void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
 #define OPT_QUIET 302
 #define OPT_OLDSTYLE 303
 #define OPT_PREFIX 304
-#define OPT_NO_ARCHIVE 305
-#define OPT_ADD_TO_ARCHIVE 306
-#define OPT_REPLACE 307
-#define OPT_DELETE_FROM_ARCHIVE 308
-#define OPT_LIST_ARCHIVE 309
+#define OPT_LOCALEDIR 305
+#define OPT_NO_ARCHIVE 306
+#define OPT_ADD_TO_ARCHIVE 307
+#define OPT_REPLACE 308
+#define OPT_DELETE_FROM_ARCHIVE 309
+#define OPT_LIST_ARCHIVE 310
 #define OPT_LITTLE_ENDIAN 400
 #define OPT_BIG_ENDIAN 401
 
@@ -131,11 +138,16 @@ static const struct argp_option options[] =
     N_("Create output even if warning messages were issued") },
   { "old-style", OPT_OLDSTYLE, NULL, 0, N_("Create old-style tables") },
   { "prefix", OPT_PREFIX, N_("PATH"), 0, N_("Optional output file prefix") },
+  { "localedir", OPT_LOCALEDIR, N_("PATH"), 0,
+    N_("Optional path to locale directory e.g. /usr/lib64/locale") },
   { "posix", OPT_POSIX, NULL, 0, N_("Strictly conform to POSIX") },
   { "quiet", OPT_QUIET, NULL, 0,
     N_("Suppress warnings and information messages") },
   { "verbose", 'v', NULL, 0, N_("Print more messages") },
+
   { NULL, 0, NULL, 0, N_("Archive control:") },
+  { "archive-file", 'a', N_("FILE"), 0,
+    N_("locale-archive file to use instead of default")},
   { "no-archive", OPT_NO_ARCHIVE, NULL, 0,
     N_("Don't add new data to archive") },
   { "add-to-archive", OPT_ADD_TO_ARCHIVE, NULL, 0,
@@ -178,6 +190,9 @@ static struct argp argp =
 /* Prototypes for local functions.  */
 static void error_print (void);
 static const char *construct_output_path (char *path);
+static const char *construct_prefix_path (const char *prefix,
+					  const char *localedir,
+					  const char *path);
 static const char *normalize_codeset (const char *codeset, size_t name_len);
 
 
@@ -189,6 +204,8 @@ main (int argc, char *argv[])
   struct charmap_t *charmap;
   struct localedef_t global;
   int remaining;
+  struct locarhandle ah;
+  const char *prefix_archive_file = NULL;
 
   /* Set initial values for global variables.  */
   copy_list = NULL;
@@ -207,14 +224,34 @@ main (int argc, char *argv[])
   argp_err_exit_status = 4;
   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
 
+  /* Use the user-specified archive file or NULL (default).  */
+  ah.fname = archive_file;
+  if (output_prefix != NULL || output_localedir != NULL || archive_file != NULL)
+    {
+      prefix_archive_file = construct_prefix_path (output_prefix ?: "",
+						   output_localedir ?: LOCALEDIR,
+						   archive_file ?: LOCALE_ARCHIVE);
+      ah.fname = prefix_archive_file;
+    }
+
   /* Handle a few special cases.  */
   if (list_archive)
-    show_archive_content (remaining > 1 ? argv[remaining] : NULL, verbose);
+    {
+      /* If using --list-archive FILE and -a FILE at the same time the
+	 archive file specified after --list-archive takes precedence.
+	 The use of -a only changes the default locale archive file.  */
+      if (remaining > 1 && remaining < argc)
+	ah.fname = construct_prefix_path (output_prefix,
+					  NULL,
+					  argv[remaining]);
+      show_archive_content (ah.fname, verbose);
+    }
   if (add_to_archive)
-    return add_locales_to_archive (argc - remaining, &argv[remaining],
+    return add_locales_to_archive (&ah, argc - remaining, &argv[remaining],
 				   replace_archive);
   if (delete_from_archive)
-    return delete_locales_from_archive (argc - remaining, &argv[remaining]);
+    return delete_locales_from_archive (&ah, argc - remaining,
+					&argv[remaining]);
 
   /* POSIX.2 requires to be verbose about missing characters in the
      character map.  */
@@ -286,9 +323,13 @@ cannot open locale definition file `%s'"), runp->name));
     {
       if (cannot_write_why != 0)
 	WITH_CUR_LOCALE (error (4, cannot_write_why, _("\
-cannot write output files to `%s'"), output_path ? : argv[remaining]));
+cannot write output files to `%s' (LOCALEDIR is `%s%s')"),
+				output_path ?: argv[remaining],
+				output_prefix ?: "",
+				output_localedir ?: LOCALEDIR));
       else
-	write_all_categories (locales, charmap, argv[remaining], output_path);
+	write_all_categories (&ah, locales, charmap,
+			      argv[remaining], output_path);
     }
   else
     WITH_CUR_LOCALE (error (4, 0, _("\
@@ -317,6 +358,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case OPT_PREFIX:
       output_prefix = arg;
       break;
+    case OPT_LOCALEDIR:
+      output_localedir = arg;
+      break;
     case OPT_NO_ARCHIVE:
       no_archive = true;
       break;
@@ -338,6 +382,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case OPT_BIG_ENDIAN:
       set_big_endian (true);
       break;
+    case 'a':
+      archive_file = arg;
+      break;
     case 'c':
       force_output = 1;
       break;
@@ -415,6 +462,26 @@ error_print (void)
 {
 }
 
+/* Construct an output path given a prefix directory, an absolute locale
+   directory and a path.  The output path is a constant and can be used
+   by any caller and must not be freed.  */
+static const char *
+construct_prefix_path (const char *prefix,
+		       const char *localedir,
+		       const char *path)
+{
+  ssize_t n;
+  char *result;
+  n = asprintf (&result, "%s%s%s%s%c",
+		prefix ?: "",
+		localedir ?: "",
+		localedir ? "/" : "",
+		path, '\0');
+  if (n < 0)
+    WITH_CUR_LOCALE (error (6, errno, _("cannot allocate path")));
+  return result;
+}
+
 
 /* The parameter to localedef describes the output path.  If it does
    contain a '/' character it is a relative path.  Otherwise it names the
@@ -458,10 +525,12 @@ construct_output_path (char *path)
       ssize_t n;
       if (normal == NULL)
 	n = asprintf (&result, "%s%s/%s%c",
-		      output_prefix ?: "", LOCALEDIR, path, '\0');
+		      output_prefix ?: "",
+		      output_localedir ?: LOCALEDIR, path, '\0');
       else
 	n = asprintf (&result, "%s%s/%.*s%s%s%c",
-		      output_prefix ?: "", LOCALEDIR,
+		      output_prefix ?: "",
+		      output_localedir ?: LOCALEDIR,
 		      (int) (startp - path), path, normal, endp, '\0');
 
       if (n < 0)
@@ -523,7 +592,7 @@ normalize_codeset (codeset, name_len)
 	  only_digit = 0;
       }
 
-  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
+  retval = (char *) xmalloc ((only_digit ? 3 : 0) + len + 1);
 
   if (retval != NULL)
     {
diff --git a/locale/programs/localedef.h b/locale/programs/localedef.h
index 7e19ff0..3baf991 100644
--- a/locale/programs/localedef.h
+++ b/locale/programs/localedef.h
@@ -135,6 +135,8 @@ extern const char *alias_file;
       setlocale (LC_CTYPE, cur_locale_);			\
   } while (0)
 
+#define LOCALE_ARCHIVE "locale-archive"
+#define ARCHIVE_NAME LOCALEDIR "/"LOCALE_ARCHIVE
 
 /* Mark given locale as to be read.  */
 extern struct localedef_t *add_to_readlist (int locale, const char *name,
@@ -165,10 +167,13 @@ extern int add_locale_to_archive (struct locarhandle *ah, const char *name,
 				  locale_data_t data, bool replace);
 
 /* Add content of named directories to locale archive.  */
-extern int add_locales_to_archive (size_t nlist, char *list[], bool replace);
+extern int add_locales_to_archive (struct locarhandle *ah,
+				   size_t nlist,
+				   char *list[], bool replace);
 
 /* Removed named locales from archive.  */
-extern int delete_locales_from_archive (size_t nlist, char *list[]);
+extern int delete_locales_from_archive (struct locarhandle *ah,
+					size_t nlist, char *list[]);
 
 /* List content of locale archive. If FNAME is non-null use that as
    the locale archive to list, otherwise the default.  */
diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c
index 49f7f1b..0ede8ea 100644
--- a/locale/programs/locarchive.c
+++ b/locale/programs/locarchive.c
@@ -57,8 +57,6 @@
 
 extern const char *output_prefix;
 
-#define ARCHIVE_NAME LOCALEDIR "/locale-archive"
-
 static const char *locnames[] =
   {
 #define DEFINE_CATEGORY(category, category_name, items, a) \
@@ -581,11 +579,10 @@ open_archive (struct locarhandle *ah, bool readonly)
       fd = open64 (archivefname, readonly ? O_RDONLY : O_RDWR);
       if (fd == -1)
 	{
-	  /* Maybe the file does not yet exist? If we are opening
-	     the default locale archive we ignore the failure and
-	     list an empty archive, otherwise we print an error
-	     and exit.  */
-	  if (errno == ENOENT && archivefname == default_fname)
+	  /* Maybe the file does not yet exist?
+	     Create it if we are not in readonly mode.
+	     If we are in readonly mode pass back an empty structure.  */
+	  if (errno == ENOENT)
 	    {
 	      if (readonly)
 		{
@@ -1328,19 +1325,19 @@ add_locale_to_archive (ah, name, data, replace)
 }
 
 
+/* Add locales to the archive file specified in AH->FNAME or
+   the default if NULL.  */
 int
-add_locales_to_archive (nlist, list, replace)
-     size_t nlist;
-     char *list[];
-     bool replace;
+add_locales_to_archive (struct locarhandle *ah,
+			size_t nlist,
+			char *list[],
+			bool replace)
 {
-  struct locarhandle ah;
   int result = 0;
 
   /* Open the archive.  This call never returns if we cannot
      successfully open the archive.  */
-  ah.fname = NULL;
-  open_archive (&ah, false);
+  open_archive (ah, false);
 
   while (nlist-- > 0)
     {
@@ -1514,7 +1511,7 @@ add_locales_to_archive (nlist, list, replace)
 	  continue;
 	}
 
-      result |= add_locale_to_archive (&ah, basename (fname), data, replace);
+      result |= add_locale_to_archive (ah, basename (fname), data, replace);
 
       for (cnt = 0; cnt < __LC_LAST; ++cnt)
 	if (cnt != LC_ALL)
@@ -1522,28 +1519,28 @@ add_locales_to_archive (nlist, list, replace)
     }
 
   /* We are done.  */
-  close_archive (&ah);
+  close_archive (ah);
 
   return result;
 }
 
 
+/* Delete the listed locales from archive AH->FNAME or the default
+   archive if NULL.  */
 int
-delete_locales_from_archive (nlist, list)
-     size_t nlist;
-     char *list[];
+delete_locales_from_archive (struct locarhandle *ah,
+			     size_t nlist,
+			     char *list[])
 {
-  struct locarhandle ah;
   struct locarhead *head;
   struct namehashent *namehashtab;
 
   /* Open the archive.  This call never returns if we cannot
      successfully open the archive.  */
-  ah.fname = NULL;
-  open_archive (&ah, false);
+  open_archive (ah, false);
 
-  head = ah.addr;
-  namehashtab = (struct namehashent *) ((char *) ah.addr
+  head = ah->addr;
+  namehashtab = (struct namehashent *) ((char *) ah->addr
 					+ GET (head->namehash_offset));
 
   while (nlist-- > 0)
@@ -1565,7 +1562,7 @@ delete_locales_from_archive (nlist, list)
 	{
 	  if (GET (namehashtab[idx].hashval) == hval
 	      && (strcmp (locname,
-			  ((char *) ah.addr
+			  ((char *) ah->addr
 			   + GET (namehashtab[idx].name_offset)))
 		  == 0))
 	    {
@@ -1584,7 +1581,7 @@ delete_locales_from_archive (nlist, list)
 	error (0, 0, _("locale \"%s\" not in archive"), locname);
     }
 
-  close_archive (&ah);
+  close_archive (ah);
 
   return 0;
 }
diff --git a/locale/programs/locfile.c b/locale/programs/locfile.c
index 33da52e..51ecfcf 100644
--- a/locale/programs/locfile.c
+++ b/locale/programs/locfile.c
@@ -326,7 +326,7 @@ static void (*const write_funcs[]) (struct localedef_t *,
 
 
 void
-write_all_categories (struct localedef_t *definitions,
+write_all_categories (struct locarhandle *ah, struct localedef_t *definitions,
 		      const struct charmap_t *charmap, const char *locname,
 		      const char *output_path)
 {
@@ -338,19 +338,15 @@ write_all_categories (struct localedef_t *definitions,
 
   if (! no_archive)
     {
-      /* The data has to be added to the archive.  Do this now.  */
-      struct locarhandle ah;
-
       /* Open the archive.  This call never returns if we cannot
 	 successfully open the archive.  */
-      ah.fname = NULL;
-      open_archive (&ah, false);
+      open_archive (ah, false);
 
-      if (add_locale_to_archive (&ah, locname, to_archive, true) != 0)
+      if (add_locale_to_archive (ah, locname, to_archive, true) != 0)
 	error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
 
       /* We are done.  */
-      close_archive (&ah);
+      close_archive (ah);
     }
 }
 
diff --git a/locale/programs/locfile.h b/locale/programs/locfile.h
index 6fc441b..8dabb6d 100644
--- a/locale/programs/locfile.h
+++ b/locale/programs/locfile.h
@@ -64,7 +64,8 @@ extern void check_all_categories (struct localedef_t *definitions,
 				  const struct charmap_t *charmap);
 
 /* Write out all locale categories.  */
-extern void write_all_categories (struct localedef_t *definitions,
+extern void write_all_categories (struct locarhandle *ah,
+				  struct localedef_t *definitions,
 				  const struct charmap_t *charmap,
 				  const char *locname,
 				  const char *output_path);
