Use clock_settime to implement stime; withdraw stime.
[glibc.git] / locale / programs / locfile.c
blobf719c496c0a94ab6e2f197c9436130305249038e
1 /* Copyright (C) 1996-2019 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1996.
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.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
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>
34 #include "../../crypt/md5.h"
35 #include "localedef.h"
36 #include "localeinfo.h"
37 #include "locfile.h"
38 #include "simple-hash.h"
40 #include "locfile-kw.h"
42 #define obstack_chunk_alloc xmalloc
43 #define obstack_chunk_free free
45 /* Temporary storage of the locale data before writing it to the archive. */
46 static locale_data_t to_archive;
49 int
50 locfile_read (struct localedef_t *result, const struct charmap_t *charmap)
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;
58 /* If no repertoire name was specified use the global one. */
59 if (repertoire_name == NULL)
60 repertoire_name = repertoire_global;
62 /* Open the locale definition file. */
63 ldfile = lr_open (filename, locfile_hash);
64 if (ldfile == NULL)
66 if (filename != NULL && filename[0] != '/')
68 char *i18npath = getenv ("I18NPATH");
69 if (i18npath != NULL && *i18npath != '\0')
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);
78 while (ldfile == NULL
79 && (next = strsep (&i18npath, ":")) != NULL)
81 stpcpy (stpcpy (stpcpy (path, next), "/locales/"), filename);
83 ldfile = lr_open (path, locfile_hash);
85 if (ldfile == NULL)
87 stpcpy (stpcpy (stpcpy (path, next), "/"), filename);
89 ldfile = lr_open (path, locfile_hash);
94 /* Test in the default directory. */
95 if (ldfile == NULL)
97 char path[strlen (filename) + 1 + sizeof (LOCSRCDIR)];
99 stpcpy (stpcpy (stpcpy (path, LOCSRCDIR), "/"), filename);
100 ldfile = lr_open (path, locfile_hash);
104 if (ldfile == NULL)
105 return 1;
108 /* Parse locale definition file and store result in RESULT. */
109 while (1)
111 struct token *now = lr_token (ldfile, charmap, NULL, NULL, verbose);
112 enum token_t nowtok = now->tok;
113 struct token *arg;
115 if (nowtok == tok_eof)
116 break;
118 if (nowtok == tok_eol)
119 /* Ignore empty lines. */
120 continue;
122 switch (nowtok)
124 case tok_escape_char:
125 case tok_comment_char:
126 /* We need an argument. */
127 arg = lr_token (ldfile, charmap, NULL, NULL, verbose);
129 if (arg->tok != tok_ident)
131 SYNTAX_ERROR (_("bad argument"));
132 continue;
135 if (arg->val.str.lenmb != 1)
137 lr_error (ldfile, _("\
138 argument to `%s' must be a single character"),
139 nowtok == tok_escape_char
140 ? "escape_char" : "comment_char");
142 lr_ignore_rest (ldfile, 0);
143 continue;
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;
152 case tok_repertoiremap:
153 /* We need an argument. */
154 arg = lr_token (ldfile, charmap, NULL, NULL, verbose);
156 if (arg->tok != tok_ident)
158 SYNTAX_ERROR (_("bad argument"));
159 continue;
162 if (repertoire_name == NULL)
164 char *newp = alloca (arg->val.str.lenmb + 1);
166 *((char *) mempcpy (newp, arg->val.str.startmb,
167 arg->val.str.lenmb)) = '\0';
168 repertoire_name = newp;
170 break;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
256 default:
257 SYNTAX_ERROR (_("\
258 syntax error: not inside a locale definition section"));
259 continue;
262 /* The rest of the line must be empty. */
263 lr_ignore_rest (ldfile, 1);
266 /* We read all of the file. */
267 lr_close (ldfile);
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;
273 return 0;
277 /* Semantic checking of locale specifications. */
279 static void (*const check_funcs[]) (struct localedef_t *,
280 const struct charmap_t *) =
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
296 void
297 check_all_categories (struct localedef_t *definitions,
298 const struct charmap_t *charmap)
300 int cnt;
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);
308 /* Writing the locale data files. All files use the same output_path. */
310 static void (*const write_funcs[]) (struct localedef_t *,
311 const struct charmap_t *, const char *) =
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
328 void
329 write_all_categories (struct localedef_t *definitions,
330 const struct charmap_t *charmap, const char *locname,
331 const char *output_path)
333 int cnt;
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);
339 if (! no_archive)
341 /* The data has to be added to the archive. Do this now. */
342 struct locarhandle ah;
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);
349 if (add_locale_to_archive (&ah, locname, to_archive, true) != 0)
350 error (EXIT_FAILURE, errno, _("cannot add to locale archive"));
352 /* We are done. */
353 close_archive (&ah);
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)
363 size_t len;
364 char *base, *p;
365 struct stat64 output_stat;
366 DIR *dirp;
367 int nelems;
368 const char **elems;
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;
380 p--;
381 while (p > base && p[-1] != '/');
382 if (p == base)
383 return NULL;
384 *--p = '\0';
385 len = p - base;
387 /* Get the properties of output_path. */
388 if (lstat64 (output_path, &output_stat) < 0 || !S_ISDIR (output_stat.st_mode))
389 return NULL;
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 (;;)
399 struct dirent64 *other_dentry;
400 const char *other_name;
401 char *other_path;
402 struct stat64 other_stat;
404 other_dentry = readdir64 (dirp);
405 if (other_dentry == NULL)
406 break;
408 other_name = other_dentry->d_name;
409 if (strcmp (other_name, ".") == 0 || strcmp (other_name, "..") == 0)
410 continue;
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);
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)
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;
432 else
433 free (other_path);
435 closedir (dirp);
437 if (elems != NULL)
438 elems[nelems] = NULL;
439 return elems;
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)
449 static const char *last_output_path;
450 static const char **last_result;
452 if (output_path != last_output_path)
454 if (last_result != NULL)
456 const char **p;
458 for (p = last_result; *p != NULL; p++)
459 free ((char *) *p);
460 free (last_result);
463 last_output_path = output_path;
464 last_result = siblings_uncached (output_path);
466 return last_result;
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)
474 char *buf = (char *) bufarea;
476 while (nbyte > 0)
478 ssize_t retval = read (fd, buf, nbyte);
480 if (retval == 0)
481 break;
482 else if (retval > 0)
484 buf += retval;
485 nbyte -= retval;
487 else if (errno != EINTR)
488 return retval;
490 return buf - (char *) bufarea;
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)
500 int fd1, fd2;
501 int ret = -1;
503 fd1 = open (filename1, O_RDONLY);
504 if (fd1 >= 0)
506 fd2 = open (filename2, O_RDONLY);
507 if (fd2 >= 0)
509 char *buf1 = (char *) xmalloc (2 * blocksize);
510 char *buf2 = buf1 + blocksize;
512 ret = 0;
513 while (size > 0)
515 size_t bytes = (size < blocksize ? size : blocksize);
517 if (full_read (fd1, buf1, bytes) < (ssize_t) bytes)
519 ret = -1;
520 break;
522 if (full_read (fd2, buf2, bytes) < (ssize_t) bytes)
524 ret = -1;
525 break;
527 if (memcmp (buf1, buf2, bytes) != 0)
529 ret = 1;
530 break;
532 size -= bytes;
535 free (buf1);
536 close (fd2);
538 close (fd1);
540 return ret;
543 /* True if the locale files use the opposite endianness to the
544 machine running localedef. */
545 bool swap_endianness_p;
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)
555 if (file->structure_stage < 2)
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;
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)
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;
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)
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);
587 /* Record that FILE's next element contains no data. */
588 void
589 add_locale_empty (struct locale_file *file)
591 record_offset (file);
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)
598 record_offset (file);
599 obstack_grow (&file->data, data, size);
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)
607 size_t size = obstack_object_size (obstack);
608 record_offset (file);
609 obstack_grow (&file->data, obstack_finish (obstack), size);
612 /* Use STRING as FILE's next element. */
613 void
614 add_locale_string (struct locale_file *file, const char *string)
616 record_offset (file);
617 obstack_grow (&file->data, string, strlen (string) + 1);
620 /* Likewise for wide strings. */
621 void
622 add_locale_wstring (struct locale_file *file, const uint32_t *string)
624 add_locale_uint32_array (file, string, wcslen ((const wchar_t *) string) + 1);
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)
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));
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)
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);
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)
653 record_offset (file);
654 obstack_1grow (&file->data, value);
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)
664 assert (file->structure_stage == 0);
665 file->structure_stage = 1;
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)
673 record_offset (file);
674 assert (file->structure_stage == 2);
675 file->structure_stage = 0;
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)
685 assert (file->structure_stage == 0);
686 file->structure_stage = 3;
689 /* End a block started by start_locale_prelude. */
690 void
691 end_locale_prelude (struct locale_file *file)
693 assert (file->structure_stage == 3);
694 file->structure_stage = 0;
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)
702 size_t cnt, step, maxiov;
703 int fd;
704 char *fname;
705 const char **other_paths = NULL;
706 uint32_t header[2];
707 size_t n_elem;
708 struct iovec vec[3];
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)
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;
730 to_archive[catidx].size = 0;
731 for (cnt = 0; cnt < n_elem; ++cnt)
732 to_archive[catidx].size += vec[cnt].iov_len;
734 /* Allocate the memory for it. */
735 to_archive[catidx].addr = xmalloc (to_archive[catidx].size);
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);
741 /* Compute the MD5 sum for the data. */
742 __md5_buffer (to_archive[catidx].addr, to_archive[catidx].size,
743 to_archive[catidx].sum);
745 return;
748 fname = xmalloc (strlen (output_path) + 2 * strlen (category) + 7);
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)
758 struct stat64 st;
760 if (stat64 (fname, &st) < 0)
762 if (mkdir (fname, 0777) >= 0)
764 fd = -1;
765 errno = EISDIR;
768 else if (!S_ISREG (st.st_mode))
770 fd = -1;
771 errno = EISDIR;
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)
780 unlink (fname);
781 fd = creat (fname, 0666);
784 if (fd == -1)
786 int save_err = errno;
788 if (errno == EISDIR)
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;
797 if (fd == -1)
799 record_error (0, save_err, _("\
800 cannot open output file `%s' for category `%s'"), fname, category);
801 free (fname);
802 return;
806 #ifdef UIO_MAXIOV
807 maxiov = UIO_MAXIOV;
808 #else
809 maxiov = sysconf (_SC_UIO_MAXIOV);
810 #endif
812 /* Write the data using writev. But we must take care for the
813 limitation of the implementation. */
814 for (cnt = 0; cnt < n_elem; cnt += step)
816 step = n_elem - cnt;
817 if (maxiov > 0)
818 step = MIN (maxiov, step);
820 if (writev (fd, &vec[cnt], step) < 0)
822 record_error (0, errno, _("\
823 failure while writing data for category `%s'"), category);
824 break;
828 close (fd);
830 /* Compare the file with the locale data files for the same category
831 in other locales, and see if we can reuse it, to save disk space.
832 If the user specified --no-hard-links to localedef then hard_links
833 is false, other_paths remains NULL and we skip the optimization
834 below. The use of --no-hard-links is distribution specific since
835 some distros have post-processing hard-link steps and so doing this
836 here is a waste of time. Worse than a waste of time in rpm-based
837 distributions it can result in build determinism issues from
838 build-to-build since some files may get a hard link in one pass but
839 not in another (if the files happened to be created in parallel). */
840 if (hard_links)
841 other_paths = siblings (output_path);
843 /* If there are other paths, then walk the sibling paths looking for
844 files with the same content so we can hard link and reduce disk
845 space usage. */
846 if (other_paths != NULL)
848 struct stat64 fname_stat;
850 if (lstat64 (fname, &fname_stat) >= 0
851 && S_ISREG (fname_stat.st_mode))
853 const char *fname_tail = fname + strlen (output_path);
854 const char **other_p;
855 int seen_count;
856 ino_t *seen_inodes;
858 seen_count = 0;
859 for (other_p = other_paths; *other_p; other_p++)
860 seen_count++;
861 seen_inodes = (ino_t *) xmalloc (seen_count * sizeof (ino_t));
862 seen_count = 0;
864 for (other_p = other_paths; *other_p; other_p++)
866 const char *other_path = *other_p;
867 size_t other_path_len = strlen (other_path);
868 char *other_fname;
869 struct stat64 other_fname_stat;
871 other_fname =
872 (char *) xmalloc (other_path_len + strlen (fname_tail) + 1);
873 memcpy (other_fname, other_path, other_path_len);
874 strcpy (other_fname + other_path_len, fname_tail);
876 if (lstat64 (other_fname, &other_fname_stat) >= 0
877 && S_ISREG (other_fname_stat.st_mode)
878 /* Consider only files on the same device.
879 Otherwise hard linking won't work anyway. */
880 && other_fname_stat.st_dev == fname_stat.st_dev
881 /* Consider only files with the same permissions.
882 Otherwise there are security risks. */
883 && other_fname_stat.st_uid == fname_stat.st_uid
884 && other_fname_stat.st_gid == fname_stat.st_gid
885 && other_fname_stat.st_mode == fname_stat.st_mode
886 /* Don't compare fname with itself. */
887 && other_fname_stat.st_ino != fname_stat.st_ino
888 /* Files must have the same size, otherwise they
889 cannot be the same. */
890 && other_fname_stat.st_size == fname_stat.st_size)
892 /* Skip this file if we have already read it (under a
893 different name). */
894 int i;
896 for (i = seen_count - 1; i >= 0; i--)
897 if (seen_inodes[i] == other_fname_stat.st_ino)
898 break;
899 if (i < 0)
901 /* Now compare fname and other_fname for real. */
902 blksize_t blocksize;
904 #ifdef _STATBUF_ST_BLKSIZE
905 blocksize = MAX (fname_stat.st_blksize,
906 other_fname_stat.st_blksize);
907 if (blocksize > 8 * 1024)
908 blocksize = 8 * 1024;
909 #else
910 blocksize = 8 * 1024;
911 #endif
913 if (compare_files (fname, other_fname,
914 fname_stat.st_size, blocksize) == 0)
916 /* Found! other_fname is identical to fname. */
917 /* Link other_fname to fname. But use a temporary
918 file, in case hard links don't work on the
919 particular filesystem. */
920 char * tmp_fname =
921 (char *) xmalloc (strlen (fname) + 4 + 1);
923 strcpy (stpcpy (tmp_fname, fname), ".tmp");
925 if (link (other_fname, tmp_fname) >= 0)
927 unlink (fname);
928 if (rename (tmp_fname, fname) < 0)
930 record_error (0, errno, _("\
931 cannot create output file `%s' for category `%s'"), fname, category);
933 free (tmp_fname);
934 free (other_fname);
935 break;
937 free (tmp_fname);
940 /* Don't compare with this file a second time. */
941 seen_inodes[seen_count++] = other_fname_stat.st_ino;
944 free (other_fname);
946 free (seen_inodes);
950 free (fname);
954 /* General handling of `copy'. */
955 void
956 handle_copy (struct linereader *ldfile, const struct charmap_t *charmap,
957 const char *repertoire_name, struct localedef_t *result,
958 enum token_t token, int locale, const char *locale_name,
959 int ignore_content)
961 struct token *now;
962 int warned = 0;
964 now = lr_token (ldfile, charmap, result, NULL, verbose);
965 if (now->tok != tok_string)
966 lr_error (ldfile, _("expecting string argument for `copy'"));
967 else if (!ignore_content)
969 if (now->val.str.startmb == NULL)
970 lr_error (ldfile, _("\
971 locale name should consist only of portable characters"));
972 else
974 (void) add_to_readlist (locale, now->val.str.startmb,
975 repertoire_name, 1, NULL);
976 result->copy_name[locale] = now->val.str.startmb;
980 lr_ignore_rest (ldfile, now->tok == tok_string);
982 /* The rest of the line must be empty and the next keyword must be
983 `END xxx'. */
984 while ((now = lr_token (ldfile, charmap, result, NULL, verbose))->tok
985 != tok_end && now->tok != tok_eof)
987 if (warned == 0)
989 lr_error (ldfile, _("\
990 no other keyword shall be specified when `copy' is used"));
991 warned = 1;
994 lr_ignore_rest (ldfile, 0);
997 if (now->tok != tok_eof)
999 /* Handle `END xxx'. */
1000 now = lr_token (ldfile, charmap, result, NULL, verbose);
1002 if (now->tok != token)
1003 lr_error (ldfile, _("\
1004 `%1$s' definition does not end with `END %1$s'"), locale_name);
1006 lr_ignore_rest (ldfile, now->tok == token);
1008 else
1009 /* When we come here we reached the end of the file. */
1010 lr_error (ldfile, _("%s: premature end of file"), locale_name);