Smack: add the execute lable to ldconfig
[platform/upstream/glibc.git] / locale / programs / locfile.c
1 /* Copyright (C) 1996-2015 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <assert.h>
32 #include <wchar.h>
33
34 #include "../../crypt/md5.h"
35 #include "localedef.h"
36 #include "localeinfo.h"
37 #include "locfile.h"
38 #include "simple-hash.h"
39
40 #include "locfile-kw.h"
41
42 #define obstack_chunk_alloc xmalloc
43 #define obstack_chunk_free free
44
45 /* Temporary storage of the locale data before writing it to the archive.  */
46 static locale_data_t to_archive;
47
48
49 int
50 locfile_read (struct localedef_t *result, const struct charmap_t *charmap)
51 {
52   const char *filename = result->name;
53   const char *repertoire_name = result->repertoire_name;
54   int locale_mask = result->needed & ~result->avail;
55   struct linereader *ldfile;
56   int not_here = ALL_LOCALES;
57
58   /* If no repertoire name was specified use the global one.  */
59   if (repertoire_name == NULL)
60     repertoire_name = repertoire_global;
61
62   /* Open the locale definition file.  */
63   ldfile = lr_open (filename, locfile_hash);
64   if (ldfile == NULL)
65     {
66       if (filename != NULL && filename[0] != '/')
67         {
68           char *i18npath = getenv ("I18NPATH");
69           if (i18npath != NULL && *i18npath != '\0')
70             {
71               const size_t pathlen = strlen (i18npath);
72               char i18npathbuf[pathlen + 1];
73               char path[strlen (filename) + 1 + pathlen
74                         + sizeof ("/locales/") - 1];
75               char *next;
76               i18npath = memcpy (i18npathbuf, i18npath, pathlen + 1);
77
78               while (ldfile == NULL
79                      && (next = strsep (&i18npath, ":")) != NULL)
80                 {
81                   stpcpy (stpcpy (stpcpy (path, next), "/locales/"), filename);
82
83                   ldfile = lr_open (path, locfile_hash);
84
85                   if (ldfile == NULL)
86                     {
87                       stpcpy (stpcpy (stpcpy (path, next), "/"), filename);
88
89                       ldfile = lr_open (path, locfile_hash);
90                     }
91                 }
92             }
93
94           /* Test in the default directory.  */
95           if (ldfile == NULL)
96             {
97               char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
98
99               stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
100               ldfile = lr_open (path, locfile_hash);
101             }
102         }
103
104       if (ldfile == NULL)
105         return 1;
106     }
107
108     /* Parse locale definition file and store result in RESULT.  */
109   while (1)
110     {
111       struct token *now = lr_token (ldfile, charmap, NULL, NULL, verbose);
112       enum token_t nowtok = now->tok;
113       struct token *arg;
114
115       if (nowtok == tok_eof)
116         break;
117
118       if (nowtok == tok_eol)
119         /* Ignore empty lines.  */
120         continue;
121
122       switch (nowtok)
123         {
124         case tok_escape_char:
125         case tok_comment_char:
126           /* We need an argument.  */
127           arg = lr_token (ldfile, charmap, NULL, NULL, verbose);
128
129           if (arg->tok != tok_ident)
130             {
131               SYNTAX_ERROR (_("bad argument"));
132               continue;
133             }
134
135           if (arg->val.str.lenmb != 1)
136             {
137               lr_error (ldfile, _("\
138 argument to `%s' must be a single character"),
139                         nowtok == tok_escape_char
140                         ? "escape_char" : "comment_char");
141
142               lr_ignore_rest (ldfile, 0);
143               continue;
144             }
145
146           if (nowtok == tok_escape_char)
147             ldfile->escape_char = *arg->val.str.startmb;
148           else
149             ldfile->comment_char = *arg->val.str.startmb;
150           break;
151
152         case tok_repertoiremap:
153           /* We need an argument.  */
154           arg = lr_token (ldfile, charmap, NULL, NULL, verbose);
155
156           if (arg->tok != tok_ident)
157             {
158               SYNTAX_ERROR (_("bad argument"));
159               continue;
160             }
161
162           if (repertoire_name == NULL)
163             {
164               char *newp = alloca (arg->val.str.lenmb + 1);
165
166               *((char *) mempcpy (newp, arg->val.str.startmb,
167                                   arg->val.str.lenmb)) = '\0';
168               repertoire_name = newp;
169             }
170           break;
171
172         case tok_lc_ctype:
173           ctype_read (ldfile, result, charmap, repertoire_name,
174                       (locale_mask & CTYPE_LOCALE) == 0);
175           result->avail |= locale_mask & CTYPE_LOCALE;
176           not_here ^= CTYPE_LOCALE;
177           continue;
178
179         case tok_lc_collate:
180           collate_read (ldfile, result, charmap, repertoire_name,
181                         (locale_mask & COLLATE_LOCALE) == 0);
182           result->avail |= locale_mask & COLLATE_LOCALE;
183           not_here ^= COLLATE_LOCALE;
184           continue;
185
186         case tok_lc_monetary:
187           monetary_read (ldfile, result, charmap, repertoire_name,
188                          (locale_mask & MONETARY_LOCALE) == 0);
189           result->avail |= locale_mask & MONETARY_LOCALE;
190           not_here ^= MONETARY_LOCALE;
191           continue;
192
193         case tok_lc_numeric:
194           numeric_read (ldfile, result, charmap, repertoire_name,
195                         (locale_mask & NUMERIC_LOCALE) == 0);
196           result->avail |= locale_mask & NUMERIC_LOCALE;
197           not_here ^= NUMERIC_LOCALE;
198           continue;
199
200         case tok_lc_time:
201           time_read (ldfile, result, charmap, repertoire_name,
202                      (locale_mask & TIME_LOCALE) == 0);
203           result->avail |= locale_mask & TIME_LOCALE;
204           not_here ^= TIME_LOCALE;
205           continue;
206
207         case tok_lc_messages:
208           messages_read (ldfile, result, charmap, repertoire_name,
209                          (locale_mask & MESSAGES_LOCALE) == 0);
210           result->avail |= locale_mask & MESSAGES_LOCALE;
211           not_here ^= MESSAGES_LOCALE;
212           continue;
213
214         case tok_lc_paper:
215           paper_read (ldfile, result, charmap, repertoire_name,
216                       (locale_mask & PAPER_LOCALE) == 0);
217           result->avail |= locale_mask & PAPER_LOCALE;
218           not_here ^= PAPER_LOCALE;
219           continue;
220
221         case tok_lc_name:
222           name_read (ldfile, result, charmap, repertoire_name,
223                      (locale_mask & NAME_LOCALE) == 0);
224           result->avail |= locale_mask & NAME_LOCALE;
225           not_here ^= NAME_LOCALE;
226           continue;
227
228         case tok_lc_address:
229           address_read (ldfile, result, charmap, repertoire_name,
230                         (locale_mask & ADDRESS_LOCALE) == 0);
231           result->avail |= locale_mask & ADDRESS_LOCALE;
232           not_here ^= ADDRESS_LOCALE;
233           continue;
234
235         case tok_lc_telephone:
236           telephone_read (ldfile, result, charmap, repertoire_name,
237                           (locale_mask & TELEPHONE_LOCALE) == 0);
238           result->avail |= locale_mask & TELEPHONE_LOCALE;
239           not_here ^= TELEPHONE_LOCALE;
240           continue;
241
242         case tok_lc_measurement:
243           measurement_read (ldfile, result, charmap, repertoire_name,
244                             (locale_mask & MEASUREMENT_LOCALE) == 0);
245           result->avail |= locale_mask & MEASUREMENT_LOCALE;
246           not_here ^= MEASUREMENT_LOCALE;
247           continue;
248
249         case tok_lc_identification:
250           identification_read (ldfile, result, charmap, repertoire_name,
251                                (locale_mask & IDENTIFICATION_LOCALE) == 0);
252           result->avail |= locale_mask & IDENTIFICATION_LOCALE;
253           not_here ^= IDENTIFICATION_LOCALE;
254           continue;
255
256         default:
257           SYNTAX_ERROR (_("\
258 syntax error: not inside a locale definition section"));
259           continue;
260         }
261
262       /* The rest of the line must be empty.  */
263       lr_ignore_rest (ldfile, 1);
264     }
265
266   /* We read all of the file.  */
267   lr_close (ldfile);
268
269   /* Mark the categories which are not contained in the file.  We assume
270      them to be available and the default data will be used.  */
271   result->avail |= not_here;
272
273   return 0;
274 }
275
276
277 /* Semantic checking of locale specifications.  */
278
279 static void (*const check_funcs[]) (struct localedef_t *,
280                                     const struct charmap_t *) =
281 {
282   [LC_CTYPE] = ctype_finish,
283   [LC_COLLATE] = collate_finish,
284   [LC_MESSAGES] = messages_finish,
285   [LC_MONETARY] = monetary_finish,
286   [LC_NUMERIC] = numeric_finish,
287   [LC_TIME] = time_finish,
288   [LC_PAPER] = paper_finish,
289   [LC_NAME] = name_finish,
290   [LC_ADDRESS] = address_finish,
291   [LC_TELEPHONE] = telephone_finish,
292   [LC_MEASUREMENT] = measurement_finish,
293   [LC_IDENTIFICATION] = identification_finish
294 };
295
296 void
297 check_all_categories (struct localedef_t *definitions,
298                       const struct charmap_t *charmap)
299 {
300   int cnt;
301
302   for (cnt = 0; cnt < sizeof (check_funcs) / sizeof (check_funcs[0]); ++cnt)
303     if (check_funcs[cnt] != NULL)
304       check_funcs[cnt] (definitions, charmap);
305 }
306
307
308 /* Writing the locale data files.  All files use the same output_path.  */
309
310 static void (*const write_funcs[]) (struct localedef_t *,
311                                     const struct charmap_t *, const char *) =
312 {
313   [LC_CTYPE] = ctype_output,
314   [LC_COLLATE] = collate_output,
315   [LC_MESSAGES] = messages_output,
316   [LC_MONETARY] = monetary_output,
317   [LC_NUMERIC] = numeric_output,
318   [LC_TIME] = time_output,
319   [LC_PAPER] = paper_output,
320   [LC_NAME] = name_output,
321   [LC_ADDRESS] = address_output,
322   [LC_TELEPHONE] = telephone_output,
323   [LC_MEASUREMENT] = measurement_output,
324   [LC_IDENTIFICATION] = identification_output
325 };
326
327
328 void
329 write_all_categories (struct localedef_t *definitions,
330                       const struct charmap_t *charmap, const char *locname,
331                       const char *output_path)
332 {
333   int cnt;
334
335   for (cnt = 0; cnt < sizeof (write_funcs) / sizeof (write_funcs[0]); ++cnt)
336     if (write_funcs[cnt] != NULL)
337       write_funcs[cnt] (definitions, charmap, output_path);
338
339   if (! no_archive)
340     {
341       /* The data has to be added to the archive.  Do this now.  */
342       struct locarhandle ah;
343
344       /* Open the archive.  This call never returns if we cannot
345          successfully open the archive.  */
346       ah.fname = NULL;
347       open_archive (&ah, false);
348
349       if (add_locale_to_archive (&ah, locname, to_archive, true) != 0)
350         error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
351
352       /* We are done.  */
353       close_archive (&ah);
354     }
355 }
356
357
358 /* Return a NULL terminated list of the directories next to output_path
359    that have the same owner, group, permissions and device as output_path.  */
360 static const char **
361 siblings_uncached (const char *output_path)
362 {
363   size_t len;
364   char *base, *p;
365   struct stat64 output_stat;
366   DIR *dirp;
367   int nelems;
368   const char **elems;
369
370   /* Remove trailing slashes and trailing pathname component.  */
371   len = strlen (output_path);
372   base = (char *) alloca (len);
373   memcpy (base, output_path, len);
374   p = base + len;
375   while (p > base && p[-1] == '/')
376     p--;
377   if (p == base)
378     return NULL;
379   do
380     p--;
381   while (p > base && p[-1] != '/');
382   if (p == base)
383     return NULL;
384   *--p = '\0';
385   len = p - base;
386
387   /* Get the properties of output_path.  */
388   if (lstat64 (output_path, &output_stat) < 0 || !S_ISDIR (output_stat.st_mode))
389     return NULL;
390
391   /* Iterate through the directories in base directory.  */
392   dirp = opendir (base);
393   if (dirp == NULL)
394     return NULL;
395   nelems = 0;
396   elems = NULL;
397   for (;;)
398     {
399       struct dirent64 *other_dentry;
400       const char *other_name;
401       char *other_path;
402       struct stat64 other_stat;
403
404       other_dentry = readdir64 (dirp);
405       if (other_dentry == NULL)
406         break;
407
408       other_name = other_dentry->d_name;
409       if (strcmp (other_name, ".") == 0 || strcmp (other_name, "..") == 0)
410         continue;
411
412       other_path = (char *) xmalloc (len + 1 + strlen (other_name) + 2);
413       memcpy (other_path, base, len);
414       other_path[len] = '/';
415       strcpy (other_path + len + 1, other_name);
416
417       if (lstat64 (other_path, &other_stat) >= 0
418           && S_ISDIR (other_stat.st_mode)
419           && other_stat.st_uid == output_stat.st_uid
420           && other_stat.st_gid == output_stat.st_gid
421           && other_stat.st_mode == output_stat.st_mode
422           && other_stat.st_dev == output_stat.st_dev)
423         {
424           /* Found a subdirectory.  Add a trailing slash and store it.  */
425           p = other_path + len + 1 + strlen (other_name);
426           *p++ = '/';
427           *p = '\0';
428           elems = (const char **) xrealloc ((char *) elems,
429                                             (nelems + 2) * sizeof (char **));
430           elems[nelems++] = other_path;
431         }
432       else
433         free (other_path);
434     }
435   closedir (dirp);
436
437   if (elems != NULL)
438     elems[nelems] = NULL;
439   return elems;
440 }
441
442
443 /* Return a NULL terminated list of the directories next to output_path
444    that have the same owner, group, permissions and device as output_path.
445    Cache the result for future calls.  */
446 static const char **
447 siblings (const char *output_path)
448 {
449   static const char *last_output_path;
450   static const char **last_result;
451
452   if (output_path != last_output_path)
453     {
454       if (last_result != NULL)
455         {
456           const char **p;
457
458           for (p = last_result; *p != NULL; p++)
459             free ((char *) *p);
460           free (last_result);
461         }
462
463       last_output_path = output_path;
464       last_result = siblings_uncached (output_path);
465     }
466   return last_result;
467 }
468
469
470 /* Read as many bytes from a file descriptor as possible.  */
471 static ssize_t
472 full_read (int fd, void *bufarea, size_t nbyte)
473 {
474   char *buf = (char *) bufarea;
475
476   while (nbyte > 0)
477     {
478       ssize_t retval = read (fd, buf, nbyte);
479
480       if (retval == 0)
481         break;
482       else if (retval > 0)
483         {
484           buf += retval;
485           nbyte -= retval;
486         }
487       else if (errno != EINTR)
488         return retval;
489     }
490   return buf - (char *) bufarea;
491 }
492
493
494 /* Compare the contents of two regular files of the same size.  Return 0
495    if they are equal, 1 if they are different, or -1 if an error occurs.  */
496 static int
497 compare_files (const char *filename1, const char *filename2, size_t size,
498                size_t blocksize)
499 {
500   int fd1, fd2;
501   int ret = -1;
502
503   fd1 = open (filename1, O_RDONLY);
504   if (fd1 >= 0)
505     {
506       fd2 = open (filename2, O_RDONLY);
507       if (fd2 >= 0)
508         {
509           char *buf1 = (char *) xmalloc (2 * blocksize);
510           char *buf2 = buf1 + blocksize;
511
512           ret = 0;
513           while (size > 0)
514             {
515               size_t bytes = (size < blocksize ? size : blocksize);
516
517               if (full_read (fd1, buf1, bytes) < (ssize_t) bytes)
518                 {
519                   ret = -1;
520                   break;
521                 }
522               if (full_read (fd2, buf2, bytes) < (ssize_t) bytes)
523                 {
524                   ret = -1;
525                   break;
526                 }
527               if (memcmp (buf1, buf2, bytes) != 0)
528                 {
529                   ret = 1;
530                   break;
531                 }
532               size -= bytes;
533             }
534
535           free (buf1);
536           close (fd2);
537         }
538       close (fd1);
539     }
540   return ret;
541 }
542
543 /* True if the locale files use the opposite endianness to the
544    machine running localedef.  */
545 bool swap_endianness_p;
546
547 /* When called outside a start_locale_structure/end_locale_structure
548    or start_locale_prelude/end_locale_prelude block, record that the
549    next byte in FILE's obstack will be the first byte of a new element.
550    Do likewise for the first call inside a start_locale_structure/
551    end_locale_structure block.  */
552 static void
553 record_offset (struct locale_file *file)
554 {
555   if (file->structure_stage < 2)
556     {
557       assert (file->next_element < file->n_elements);
558       file->offsets[file->next_element++]
559         = (obstack_object_size (&file->data)
560            + (file->n_elements + 2) * sizeof (uint32_t));
561       if (file->structure_stage == 1)
562         file->structure_stage = 2;
563     }
564 }
565
566 /* Initialize FILE for a new output file.  N_ELEMENTS is the number
567    of elements in the file.  */
568 void
569 init_locale_data (struct locale_file *file, size_t n_elements)
570 {
571   file->n_elements = n_elements;
572   file->next_element = 0;
573   file->offsets = xmalloc (sizeof (uint32_t) * n_elements);
574   obstack_init (&file->data);
575   file->structure_stage = 0;
576 }
577
578 /* Align the size of FILE's obstack object to BOUNDARY bytes.  */
579 void
580 align_locale_data (struct locale_file *file, size_t boundary)
581 {
582   size_t size = -obstack_object_size (&file->data) & (boundary - 1);
583   obstack_blank (&file->data, size);
584   memset (obstack_next_free (&file->data) - size, 0, size);
585 }
586
587 /* Record that FILE's next element contains no data.  */
588 void
589 add_locale_empty (struct locale_file *file)
590 {
591   record_offset (file);
592 }
593
594 /* Record that FILE's next element consists of SIZE bytes starting at DATA.  */
595 void
596 add_locale_raw_data (struct locale_file *file, const void *data, size_t size)
597 {
598   record_offset (file);
599   obstack_grow (&file->data, data, size);
600 }
601
602 /* Finish the current object on OBSTACK and use it as the data for FILE's
603    next element.  */
604 void
605 add_locale_raw_obstack (struct locale_file *file, struct obstack *obstack)
606 {
607   size_t size = obstack_object_size (obstack);
608   record_offset (file);
609   obstack_grow (&file->data, obstack_finish (obstack), size);
610 }
611
612 /* Use STRING as FILE's next element.  */
613 void
614 add_locale_string (struct locale_file *file, const char *string)
615 {
616   record_offset (file);
617   obstack_grow (&file->data, string, strlen (string) + 1);
618 }
619
620 /* Likewise for wide strings.  */
621 void
622 add_locale_wstring (struct locale_file *file, const uint32_t *string)
623 {
624   add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
625 }
626
627 /* Record that FILE's next element is the 32-bit integer VALUE.  */
628 void
629 add_locale_uint32 (struct locale_file *file, uint32_t value)
630 {
631   align_locale_data (file, LOCFILE_ALIGN);
632   record_offset (file);
633   value = maybe_swap_uint32 (value);
634   obstack_grow (&file->data, &value, sizeof (value));
635 }
636
637 /* Record that FILE's next element is an array of N_ELEMS integers
638    starting at DATA.  */
639 void
640 add_locale_uint32_array (struct locale_file *file,
641                          const uint32_t *data, size_t n_elems)
642 {
643   align_locale_data (file, LOCFILE_ALIGN);
644   record_offset (file);
645   obstack_grow (&file->data, data, n_elems * sizeof (uint32_t));
646   maybe_swap_uint32_obstack (&file->data, n_elems);
647 }
648
649 /* Record that FILE's next element is the single byte given by VALUE.  */
650 void
651 add_locale_char (struct locale_file *file, char value)
652 {
653   record_offset (file);
654   obstack_1grow (&file->data, value);
655 }
656
657 /* Start building an element that contains several different pieces of data.
658    Subsequent calls to add_locale_* will add data to the same element up
659    till the next call to end_locale_structure.  The element's alignment
660    is dictated by the first piece of data added to it.  */
661 void
662 start_locale_structure (struct locale_file *file)
663 {
664   assert (file->structure_stage == 0);
665   file->structure_stage = 1;
666 }
667
668 /* Finish a structure element that was started by start_locale_structure.
669    Empty structures are OK and behave like add_locale_empty.  */
670 void
671 end_locale_structure (struct locale_file *file)
672 {
673   record_offset (file);
674   assert (file->structure_stage == 2);
675   file->structure_stage = 0;
676 }
677
678 /* Start building data that goes before the next element's recorded offset.
679    Subsequent calls to add_locale_* will add data to the file without
680    treating any of it as the start of a new element.  Calling
681    end_locale_prelude switches back to the usual behavior.  */
682 void
683 start_locale_prelude (struct locale_file *file)
684 {
685   assert (file->structure_stage == 0);
686   file->structure_stage = 3;
687 }
688
689 /* End a block started by start_locale_prelude.  */
690 void
691 end_locale_prelude (struct locale_file *file)
692 {
693   assert (file->structure_stage == 3);
694   file->structure_stage = 0;
695 }
696
697 /* Write a locale file, with contents given by FILE.  */
698 void
699 write_locale_data (const char *output_path, int catidx, const char *category,
700                    struct locale_file *file)
701 {
702   size_t cnt, step, maxiov;
703   int fd;
704   char *fname;
705   const char **other_paths;
706   uint32_t header[2];
707   size_t n_elem;
708   struct iovec vec[3];
709
710   assert (file->n_elements == file->next_element);
711   header[0] = LIMAGIC (catidx);
712   header[1] = file->n_elements;
713   vec[0].iov_len = sizeof (header);
714   vec[0].iov_base = header;
715   vec[1].iov_len = sizeof (uint32_t) * file->n_elements;
716   vec[1].iov_base = file->offsets;
717   vec[2].iov_len = obstack_object_size (&file->data);
718   vec[2].iov_base = obstack_finish (&file->data);
719   maybe_swap_uint32_array (vec[0].iov_base, 2);
720   maybe_swap_uint32_array (vec[1].iov_base, file->n_elements);
721   n_elem = 3;
722   if (! no_archive)
723     {
724       /* The data will be added to the archive.  For now we simply
725          generate the image which will be written.  First determine
726          the size.  */
727       int cnt;
728       void *endp;
729
730       to_archive[catidx].size = 0;
731       for (cnt = 0; cnt < n_elem; ++cnt)
732         to_archive[catidx].size += vec[cnt].iov_len;
733
734       /* Allocate the memory for it.  */
735       to_archive[catidx].addr = xmalloc (to_archive[catidx].size);
736
737       /* Fill it in.  */
738       for (cnt = 0, endp = to_archive[catidx].addr; cnt < n_elem; ++cnt)
739         endp = mempcpy (endp, vec[cnt].iov_base, vec[cnt].iov_len);
740
741       /* Compute the MD5 sum for the data.  */
742       __md5_buffer (to_archive[catidx].addr, to_archive[catidx].size,
743                     to_archive[catidx].sum);
744
745       return;
746     }
747
748   fname = xmalloc (strlen (output_path) + 2 * strlen (category) + 7);
749
750   /* Normally we write to the directory pointed to by the OUTPUT_PATH.
751      But for LC_MESSAGES we have to take care for the translation
752      data.  This means we need to have a directory LC_MESSAGES in
753      which we place the file under the name SYS_LC_MESSAGES.  */
754   sprintf (fname, "%s%s", output_path, category);
755   fd = -2;
756   if (strcmp (category, "LC_MESSAGES") == 0)
757     {
758       struct stat64 st;
759
760       if (stat64 (fname, &st) < 0)
761         {
762           if (mkdir (fname, 0777) >= 0)
763             {
764               fd = -1;
765               errno = EISDIR;
766             }
767         }
768       else if (!S_ISREG (st.st_mode))
769         {
770           fd = -1;
771           errno = EISDIR;
772         }
773     }
774
775   /* Create the locale file with nlinks == 1; this avoids crashing processes
776      which currently use the locale and damaging files belonging to other
777      locales as well.  */
778   if (fd == -2)
779     {
780       unlink (fname);
781       fd = creat (fname, 0666);
782     }
783
784   if (fd == -1)
785     {
786       int save_err = errno;
787
788       if (errno == EISDIR)
789         {
790           sprintf (fname, "%1$s%2$s/SYS_%2$s", output_path, category);
791           unlink (fname);
792           fd = creat (fname, 0666);
793           if (fd == -1)
794             save_err = errno;
795         }
796
797       if (fd == -1)
798         {
799           if (!be_quiet)
800             WITH_CUR_LOCALE (error (0, save_err, _("\
801 cannot open output file `%s' for category `%s'"), fname, category));
802           free (fname);
803           return;
804         }
805     }
806
807 #ifdef UIO_MAXIOV
808   maxiov = UIO_MAXIOV;
809 #else
810   maxiov = sysconf (_SC_UIO_MAXIOV);
811 #endif
812
813   /* Write the data using writev.  But we must take care for the
814      limitation of the implementation.  */
815   for (cnt = 0; cnt < n_elem; cnt += step)
816     {
817       step = n_elem - cnt;
818       if (maxiov > 0)
819         step = MIN (maxiov, step);
820
821       if (writev (fd, &vec[cnt], step) < 0)
822         {
823           if (!be_quiet)
824             WITH_CUR_LOCALE (error (0, errno, _("\
825 failure while writing data for category `%s'"), category));
826           break;
827         }
828     }
829
830   close (fd);
831
832   /* Compare the file with the locale data files for the same category in
833      other locales, and see if we can reuse it, to save disk space.  */
834   other_paths = siblings (output_path);
835   if (other_paths != NULL)
836     {
837       struct stat64 fname_stat;
838
839       if (lstat64 (fname, &fname_stat) >= 0
840           && S_ISREG (fname_stat.st_mode))
841         {
842           const char *fname_tail = fname + strlen (output_path);
843           const char **other_p;
844           int seen_count;
845           ino_t *seen_inodes;
846
847           seen_count = 0;
848           for (other_p = other_paths; *other_p; other_p++)
849             seen_count++;
850           seen_inodes = (ino_t *) xmalloc (seen_count * sizeof (ino_t));
851           seen_count = 0;
852
853           for (other_p = other_paths; *other_p; other_p++)
854             {
855               const char *other_path = *other_p;
856               size_t other_path_len = strlen (other_path);
857               char *other_fname;
858               struct stat64 other_fname_stat;
859
860               other_fname =
861                 (char *) xmalloc (other_path_len + strlen (fname_tail) + 1);
862               memcpy (other_fname, other_path, other_path_len);
863               strcpy (other_fname + other_path_len, fname_tail);
864
865               if (lstat64 (other_fname, &other_fname_stat) >= 0
866                   && S_ISREG (other_fname_stat.st_mode)
867                   /* Consider only files on the same device.
868                      Otherwise hard linking won't work anyway.  */
869                   && other_fname_stat.st_dev == fname_stat.st_dev
870                   /* Consider only files with the same permissions.
871                      Otherwise there are security risks.  */
872                   && other_fname_stat.st_uid == fname_stat.st_uid
873                   && other_fname_stat.st_gid == fname_stat.st_gid
874                   && other_fname_stat.st_mode == fname_stat.st_mode
875                   /* Don't compare fname with itself.  */
876                   && other_fname_stat.st_ino != fname_stat.st_ino
877                   /* Files must have the same size, otherwise they
878                      cannot be the same.  */
879                   && other_fname_stat.st_size == fname_stat.st_size)
880                 {
881                   /* Skip this file if we have already read it (under a
882                      different name).  */
883                   int i;
884
885                   for (i = seen_count - 1; i >= 0; i--)
886                     if (seen_inodes[i] == other_fname_stat.st_ino)
887                       break;
888                   if (i < 0)
889                     {
890                       /* Now compare fname and other_fname for real.  */
891                       blksize_t blocksize;
892
893 #ifdef _STATBUF_ST_BLKSIZE
894                       blocksize = MAX (fname_stat.st_blksize,
895                                        other_fname_stat.st_blksize);
896                       if (blocksize > 8 * 1024)
897                         blocksize = 8 * 1024;
898 #else
899                       blocksize = 8 * 1024;
900 #endif
901
902                       if (compare_files (fname, other_fname,
903                                          fname_stat.st_size, blocksize) == 0)
904                         {
905                           /* Found! other_fname is identical to fname.  */
906                           /* Link other_fname to fname.  But use a temporary
907                              file, in case hard links don't work on the
908                              particular filesystem.  */
909                           char * tmp_fname =
910                             (char *) xmalloc (strlen (fname) + 4 + 1);
911
912                           strcpy (stpcpy (tmp_fname, fname), ".tmp");
913
914                           if (link (other_fname, tmp_fname) >= 0)
915                             {
916                               unlink (fname);
917                               if (rename (tmp_fname, fname) < 0)
918                                 {
919                                   if (!be_quiet)
920                                     WITH_CUR_LOCALE (error (0, errno, _("\
921 cannot create output file `%s' for category `%s'"), fname, category));
922                                 }
923                               free (tmp_fname);
924                               free (other_fname);
925                               break;
926                             }
927                           free (tmp_fname);
928                         }
929
930                       /* Don't compare with this file a second time.  */
931                       seen_inodes[seen_count++] = other_fname_stat.st_ino;
932                     }
933                 }
934               free (other_fname);
935             }
936           free (seen_inodes);
937         }
938     }
939
940   free (fname);
941 }
942
943
944 /* General handling of `copy'.  */
945 void
946 handle_copy (struct linereader *ldfile, const struct charmap_t *charmap,
947              const char *repertoire_name, struct localedef_t *result,
948              enum token_t token, int locale, const char *locale_name,
949              int ignore_content)
950 {
951   struct token *now;
952   int warned = 0;
953
954   now = lr_token (ldfile, charmap, result, NULL, verbose);
955   if (now->tok != tok_string)
956     lr_error (ldfile, _("expecting string argument for `copy'"));
957   else if (!ignore_content)
958     {
959       if (now->val.str.startmb == NULL)
960         lr_error (ldfile, _("\
961 locale name should consist only of portable characters"));
962       else
963         {
964           (void) add_to_readlist (locale, now->val.str.startmb,
965                                   repertoire_name, 1, NULL);
966           result->copy_name[locale] = now->val.str.startmb;
967         }
968     }
969
970   lr_ignore_rest (ldfile, now->tok == tok_string);
971
972   /* The rest of the line must be empty and the next keyword must be
973      `END xxx'.  */
974   while ((now = lr_token (ldfile, charmap, result, NULL, verbose))->tok
975          != tok_end && now->tok != tok_eof)
976     {
977       if (warned == 0)
978         {
979           lr_error (ldfile, _("\
980 no other keyword shall be specified when `copy' is used"));
981           warned = 1;
982         }
983
984       lr_ignore_rest (ldfile, 0);
985     }
986
987   if (now->tok != tok_eof)
988     {
989       /* Handle `END xxx'.  */
990       now = lr_token (ldfile, charmap, result, NULL, verbose);
991
992       if (now->tok != token)
993         lr_error (ldfile, _("\
994 `%1$s' definition does not end with `END %1$s'"), locale_name);
995
996       lr_ignore_rest (ldfile, now->tok == token);
997     }
998   else
999     /* When we come here we reached the end of the file.  */
1000     lr_error (ldfile, _("%s: premature end of file"), locale_name);
1001 }