localedef: Add --localedir and --archive-file options (Bug 19130)
diff mbox

Message ID 561F230E.5050801@redhat.com
State New
Headers show

Commit Message

Carlos O'Donell Oct. 15, 2015, 3:52 a.m. UTC
At present localdef accepts the following non-POSIX options:

--list-archive [FILE]

and

--prefix=PATH

The first allows you to list the contents of the default binary
locale archive via `--list-archive` or any other archive
via `--list-archive FILE` where FILE is an absolute or relative
path to the archive.

This patch does three things, and I have consciously not split
them up into three patches because they logically belong together.

(1) Enhance `--list-archive`, `--add-to-archive`, and 
    `--delete-from-archive` to honour `--prefix=PATH`.

At present the use of --prefix does not adjust the path
interpreted by --list-archive FILE . This is a mistake. We should
always honour --prefix in all of our output operations. The patch makes
--list-archive FILE honour prefix. For example if you ran
`--prefix /mnt/chroot --list-archive /usr/lib/locale/locale-archive-v2`
the final path to the locale archive file would be:
`/mnt/chroot/usr/lib/locale/locale-archive-v2`.

Similarly --add-to-archive and --delete-from-archive honour
--prefix when computing the archive to use.

e.g.
localedef --prefix="/home/carlos/tmp" --add-to-archive ./en_US.UTF-8
cannot create temporary file: /home/carlos/tmp/usr/lib64/locale/locale-archive.3vmNHw: No such file or directory

(2) Add a `--localedir=PATH` option per BZ #19130.

At present all operations are carried out against a hard-coded
LOCALEDIR e.g. $(localedir) or /usr/lib/locale. This patch adds
a --localedir=PATH option which allows you to change the value
of LOCALEDIR used in localedef. For example if you ran
`--localedir=/usr/lib64/locale --list-archive` the final path
to the locale archive file would be:
`/usr/lib64/locale/locale-archive`.

e.g.
./locale/localedef --prefix="/home/carlos/tmp" --localedir="/alt" --add-to-archive ./en_US.UTF-8
cannot create temporary file: /home/carlos/tmp/alt/locale-archive.VCqI8z: No such file or directory

(3) Add a `--archive-file=FILE`/`-a FILE` option.

At present the binary locale archive name is always `locale-archive`,
but it would be easier for distribution maintainers and developers
if localedef could be made to scan an arbitrary file. This patch
makes `--archive-file=FILE` adjust the default locale archive file
name to be FILE. For example if you ran:
`--prefix /mnt/croot --archive-file=locale-archive-v2` the final path
to the locale archive file would be:
`/mnt/chroot/usr/lib/locale/locale-archive-v2`.

With (1), (2) and (3), you have full control over the locale archive
selected by localedef:

[prefix][localedir][archive file]
|        |          |
|        |          |-> --archive-file
|        |
|        |-> --localedir
|
|-> --prefix

Sensible defaults are selected for all values based on the configuration
of glibc e.g. prefix is "", localedir is "$(localedir)" and archive file
is "locale-archive".

(a) Use of I18NPATH, LOCPATH, and change in behaviour of ENOENT for
    locale-archive.

The selection of the character maps is achieved by use of the I18NPATH
env var, and LOCPATH env var for the location of source locale data.
These environment variables do not use --prefix. Both of these variables
will fallback to the default system directory during failure to find the
required files, while the above settings for prefix/localedir/archive-file
will create the requested binary locale archive file if not found. Note
that this is a change in behaviour, previously if the non-default binary
locale archive file was not found we would issue an error (only creating
the default locale archive was supported). Now we treat all locale-archive
files the same way. It might be argued that a "--create" mode should be
used and errors issued if the file doesn't exist in all cases, but this
breaks backwards compatibility and should be avoided. The only thing we
break with this patch is using `--list-archive foo` to test if `foo`
is present and a locale-archive file, which now returns nothing, but
doesn't fail (like we did for the default locale archive).

(b) Future enhancements.

Future enhancements include more options to control locale source
path (LOCPATH) and character map locations (I18NPATH) since falling back
to the default system directories is not always desirable in a cross
or sysroot'd environment.

Tested on x86_64 to view locale archive files in non-standard paths and
to generate locale archive files in non-standard paths.

Using --help gives these addtional options:
~~~
...
      --localedir=PATH       Optional path to locale directory e.g.
                             /usr/lib64/locale
...
  -a, --archive-file=FILE    locale-archive file to use instead of default
...
~~~

OK to checkin?

2015-10-14  Carlos O'Donell  <carlos@redhat.com>

	[BZ #19130]
	* locale/programs/localedef.c (output_localedir): New variable.
	(archive_file): New variable.
	(OPT_LOCALEDIR): New macro.
	(OPT_NO_ARCHIVE, OPT_ADD_TO_ARCHIVE, OPT_REPLACE,
	OPT_DELETE_FROM_ARCHIVE, OPT_LIST_ARCHIVE): Adjust down by one.
	(options): Add --localedir option. Add --archive-file/-a option.
	(main): --list-archive FILE has precedence over -a FILE.
	Pass specified archive file (-a FILE) to callees (prefix still
	applies).
	(parse_opt): Add OPT_LOCALEDIR and store to output_localedir.
	Add 'a' and store to archive_file.
	(construct_output_path): Use output_localedir if non-NULL.
	(normalize_codeset): Use xmalloc.
	(construct_prefix_path): New function.
	* locale/programs/localedef.h: add_locales_to_archive, and
	delete_locales_from_archive accept pointer to struct locarhandle.
	* locale/programs/locarchive.c (add_locales_to_archive): Use struct
	locarhandle pointer passed by caller.
	(delete_locales_from_archive): Likewise.
	(open_archive): Always create the archive if not in readonly mode.
	(ARCHIVE_NAME): Remove.
	* locale/programs/localedef.h (LOCALE_ARCHIVE): Define.
	(ARCHIVE_NAME): Define.
	* locale/programs/locfile.c (write_all_categories): Likewise.
	* locale/programs/locfile.h: write_all_categories accepts pointer to
	struct locarhandle.

---

Cheers,
Carlos.

Comments

Marko Myllynen Oct. 15, 2015, 5:14 a.m. UTC | #1
Hi,

On 2015-10-15 06:52, Carlos O'Donell wrote:
> 
> (a) Use of I18NPATH, LOCPATH, and change in behaviour of ENOENT for
>     locale-archive.
> 
> The selection of the character maps is achieved by use of the I18NPATH
> env var, and LOCPATH env var for the location of source locale data.

are you sure about this? I was under impression it is only I18NPATH, not
LOCPATH, that affects localedef. That's also what I see on my RHEL 7 /
glibc-2.17 and what I've documented in the localedef(1) man page:

http://man7.org/linux/man-pages/man1/localedef.1.html

> These environment variables do not use --prefix. Both of these variables
> will fallback to the default system directory during failure to find the
> required files, while the above settings for prefix/localedir/archive-file
> will create the requested binary locale archive file if not found. Note
> that this is a change in behaviour, previously if the non-default binary
> locale archive file was not found we would issue an error (only creating
> the default locale archive was supported). Now we treat all locale-archive
> files the same way. It might be argued that a "--create" mode should be
> used and errors issued if the file doesn't exist in all cases, but this
> breaks backwards compatibility and should be avoided. The only thing we
> break with this patch is using `--list-archive foo` to test if `foo`
> is present and a locale-archive file, which now returns nothing, but
> doesn't fail (like we did for the default locale archive).

Once the patches have been merged, could you kindly check whether any
changes for the man page is needed? Or if you plan to implement (b)
soon, perhaps we could review the man page after that.

Thanks,
Joseph Myers Oct. 15, 2015, 11:50 a.m. UTC | #2
On Wed, 14 Oct 2015, Carlos O'Donell wrote:

> (2) Add a `--localedir=PATH` option per BZ #19130.

It's possible this option name may be confusing.  Cf. bug 14259 discussing 
the meaning of the configure --localedir option.  (I think that bug is 
only a documentation issue - install.texi needs to document exactly what 
the configure option means, without any change to what that option does.)  
Do we want the localedef option to have a meaning completely different 
from that configure option, and so possibly add to that confusion?

Also, a new feature like this should have its own NEWS entry, not just a 
number in the list of fixed bugs (even if by the time of the next release 
we have a system to generate a list with bug descriptions included).
Carlos O'Donell Oct. 16, 2015, 3:15 p.m. UTC | #3
On 10/15/2015 01:14 AM, Marko Myllynen wrote:
> Hi,
> 
> On 2015-10-15 06:52, Carlos O'Donell wrote:
>>
>> (a) Use of I18NPATH, LOCPATH, and change in behaviour of ENOENT for
>>     locale-archive.
>>
>> The selection of the character maps is achieved by use of the I18NPATH
>> env var, and LOCPATH env var for the location of source locale data.
> 
> are you sure about this? I was under impression it is only I18NPATH, not
> LOCPATH, that affects localedef. That's also what I see on my RHEL 7 /
> glibc-2.17 and what I've documented in the localedef(1) man page:
> 
> http://man7.org/linux/man-pages/man1/localedef.1.html

You are correct, only I18NPATH is used for both charmaps and locales.
I misread the sources for locfile.c and charmap.c.

>> These environment variables do not use --prefix. Both of these variables
>> will fallback to the default system directory during failure to find the
>> required files, while the above settings for prefix/localedir/archive-file
>> will create the requested binary locale archive file if not found. Note
>> that this is a change in behaviour, previously if the non-default binary
>> locale archive file was not found we would issue an error (only creating
>> the default locale archive was supported). Now we treat all locale-archive
>> files the same way. It might be argued that a "--create" mode should be
>> used and errors issued if the file doesn't exist in all cases, but this
>> breaks backwards compatibility and should be avoided. The only thing we
>> break with this patch is using `--list-archive foo` to test if `foo`
>> is present and a locale-archive file, which now returns nothing, but
>> doesn't fail (like we did for the default locale archive).
> 
> Once the patches have been merged, could you kindly check whether any
> changes for the man page is needed? Or if you plan to implement (b)
> soon, perhaps we could review the man page after that.

I will submit a followup patch to the linux man pages project.

Cheers,
Carlos.
Mike Frysinger Oct. 17, 2015, 3:45 a.m. UTC | #4
On 14 Oct 2015 23:52, Carlos O'Donell wrote:
> +    N_("Optional path to locale directory e.g. /usr/lib64/locale") },

why /usr/lib64/locale ?  seems like you should use LOCALEDIR.

> +    N_("locale-archive file to use instead of default")},

we do set up ARCHIVE_NAME which includes the full path ...

> +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",

asprintf returns an int, not ssize_t ... although i see the rest of this
program gets it wrong too ...

> +		prefix ?: "",
> +		localedir ?: "",
> +		localedir ? "/" : "",
> +		path, '\0');

what's with the \0 ?  asprintf does that for you ...
i guess the rest of this file does this weirdness too.  

> -  retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
> +  retval = (char *) xmalloc ((only_digit ? 3 : 0) + len + 1);
>  
>    if (retval != NULL)

why check if retval is NULL since you changed it to xmalloc ?

> +#define ARCHIVE_NAME LOCALEDIR "/"LOCALE_ARCHIVE

should be a space after the "/"
-mike
Carlos O'Donell Oct. 19, 2015, 11:28 p.m. UTC | #5
On 10/15/2015 07:50 AM, Joseph Myers wrote:
> On Wed, 14 Oct 2015, Carlos O'Donell wrote:
> 
>> (2) Add a `--localedir=PATH` option per BZ #19130.
> 
> It's possible this option name may be confusing.  Cf. bug 14259 discussing 
> the meaning of the configure --localedir option.  (I think that bug is 
> only a documentation issue - install.texi needs to document exactly what 
> the configure option means, without any change to what that option does.)  

It is my opinion that Andreas Schwab was wrong in comment #7:
https://sourceware.org/bugzilla/show_bug.cgi?id=14259#c7

The location of the locale archive, and binary compiled locales is localedir.

The location of the gettext message catalogs is msgcatdir.

The only way to change the location of msgcatdir is to adjust datadir.

Therefore I think the option is correct, and I'll submitted a patch
to fix bug 14259.

> Do we want the localedef option to have a meaning completely different 
> from that configure option, and so possibly add to that confusion?

No. Both options are and do mean the same thing. Unless someone can point
out something I did wrong.

> Also, a new feature like this should have its own NEWS entry, not just a 
> number in the list of fixed bugs (even if by the time of the next release 
> we have a system to generate a list with bug descriptions included).

Agreed. I will post v2 and add a NEWS entry.

Cheers,
Carlos.
Joseph Myers Oct. 19, 2015, 11:45 p.m. UTC | #6
On Mon, 19 Oct 2015, Carlos O'Donell wrote:

> The location of the locale archive, and binary compiled locales is localedir.
> 
> The location of the gettext message catalogs is msgcatdir.

No, localedir is explicitly defined in the GNU Coding Standards.  See 
make-stds.texi:

    @item localedir
    The directory for installing locale-specific message catalogs for this
    package.  By default, it should be @file{/usr/local/share/locale}, but
    it should be written as @file{$(datarootdir)/locale}.  (If you are
    using Autoconf, write it as @samp{@@localedir@@}.)  This directory
    usually has a subdirectory per locale.
Carlos O'Donell Oct. 20, 2015, 1:29 p.m. UTC | #7
On 10/19/2015 07:45 PM, Joseph Myers wrote:
> On Mon, 19 Oct 2015, Carlos O'Donell wrote:
> 
>> The location of the locale archive, and binary compiled locales is localedir.
>>
>> The location of the gettext message catalogs is msgcatdir.
> 
> No, localedir is explicitly defined in the GNU Coding Standards.  See 
> make-stds.texi:
> 
>     @item localedir
>     The directory for installing locale-specific message catalogs for this
>     package.  By default, it should be @file{/usr/local/share/locale}, but
>     it should be written as @file{$(datarootdir)/locale}.  (If you are
>     using Autoconf, write it as @samp{@@localedir@@}.)  This directory
>     usually has a subdirectory per locale.
> 

I had not looked at the GNU Coding Standards. You are correct.

In which case I think 3 things need to be done:

(1) Make sure --localedir configure option properly changes $(msgcatdir)
    to allow the user to select where glibc looks for locale-specific
    messages.

(2) Rename the uses of LOCALEDIR and $(localedir) within the glibc configury
    to avoid confusion. I suggest LOCARCHDIR and $(locarchdir).

(3) Repost my localedef patches rebased on (1) and (2).

Did I miss anything?

Cheers,
Carlos.
Joseph Myers Oct. 20, 2015, 3:17 p.m. UTC | #8
On Tue, 20 Oct 2015, Carlos O'Donell wrote:

> In which case I think 3 things need to be done:
> 
> (1) Make sure --localedir configure option properly changes $(msgcatdir)
>     to allow the user to select where glibc looks for locale-specific
>     messages.
> 
> (2) Rename the uses of LOCALEDIR and $(localedir) within the glibc configury
>     to avoid confusion. I suggest LOCARCHDIR and $(locarchdir).
> 
> (3) Repost my localedef patches rebased on (1) and (2).
> 
> Did I miss anything?

No, that seems about right.
Andreas Schwab Oct. 20, 2015, 3:54 p.m. UTC | #9
"Carlos O'Donell" <carlos@redhat.com> writes:

> (2) Rename the uses of LOCALEDIR and $(localedir) within the glibc configury
>     to avoid confusion. I suggest LOCARCHDIR and $(locarchdir).

What is a locarch?

Andreas.

Patch
diff mbox

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);