Add PT_AARCH64_MEMTAG_MTE from Linux 5.18 to elf.h
[glibc.git] / nss / makedb.c
blobd3fc1c5af9a1f488e5152487b4fdbe19839304a5
1 /* Create simple DB database from textual input.
2 Copyright (C) 1996-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <argp.h>
20 #include <assert.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <fcntl.h>
25 #include <inttypes.h>
26 #include <libintl.h>
27 #include <locale.h>
28 #include <search.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <stdint.h>
35 #include <sys/mman.h>
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #include <sys/uio.h>
39 #include "nss_db/nss_db.h"
40 #include <libc-diag.h>
42 /* Get libc version number. */
43 #include "../version.h"
45 /* The hashing function we use. */
46 #include "../intl/hash-string.h"
48 /* SELinux support. */
49 #ifdef HAVE_SELINUX
50 # include <selinux/selinux.h>
51 #endif
53 #ifndef MAP_POPULATE
54 # define MAP_POPULATE 0
55 #endif
57 #define PACKAGE _libc_intl_domainname
59 /* List of data bases. */
60 struct database
62 char dbid;
63 bool extra_string;
64 struct database *next;
65 void *entries;
66 size_t nentries;
67 size_t nhashentries;
68 stridx_t *hashtable;
69 size_t keystrlen;
70 stridx_t *keyidxtab;
71 char *keystrtab;
72 } *databases;
73 static size_t ndatabases;
74 static size_t nhashentries_total;
75 static size_t valstrlen;
76 static void *valstrtree;
77 static char *valstrtab;
78 static size_t extrastrlen;
80 /* Database entry. */
81 struct dbentry
83 stridx_t validx;
84 uint32_t hashval;
85 char str[0];
88 /* Stored string entry. */
89 struct valstrentry
91 stridx_t idx;
92 bool extra_string;
93 char str[0];
97 /* True if any entry has been added. */
98 static bool any_dbentry;
100 /* If non-zero convert key to lower case. */
101 static int to_lowercase;
103 /* If non-zero print content of input file, one entry per line. */
104 static int do_undo;
106 /* If non-zero do not print informational messages. */
107 static int be_quiet;
109 /* Name of output file. */
110 static const char *output_name;
112 /* Name and version of program. */
113 static void print_version (FILE *stream, struct argp_state *state);
114 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
116 /* Definitions of arguments for argp functions. */
117 static const struct argp_option options[] =
119 { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
120 { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
121 { "quiet", 'q', NULL, 0,
122 N_("Do not print messages while building database") },
123 { "undo", 'u', NULL, 0,
124 N_("Print content of database file, one entry a line") },
125 { "generated", 'g', N_("CHAR"), 0,
126 N_("Generated line not part of iteration") },
127 { NULL, 0, NULL, 0, NULL }
130 /* Short description of program. */
131 static const char doc[] = N_("Create simple database from textual input.");
133 /* Strings for arguments in help texts. */
134 static const char args_doc[] = N_("\
135 INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
137 /* Prototype for option handler. */
138 static error_t parse_opt (int key, char *arg, struct argp_state *state);
140 /* Function to print some extra text in the help message. */
141 static char *more_help (int key, const char *text, void *input);
143 /* Data structure to communicate with argp functions. */
144 static struct argp argp =
146 options, parse_opt, args_doc, doc, NULL, more_help
150 /* List of databases which are not part of the iteration table. */
151 static struct db_option
153 char dbid;
154 struct db_option *next;
155 } *db_options;
158 /* Prototypes for local functions. */
159 static int process_input (FILE *input, const char *inname,
160 int to_lowercase, int be_quiet);
161 static int print_database (int fd);
162 static void compute_tables (void);
163 static int write_output (int fd);
165 /* SELinux support. */
166 #ifdef HAVE_SELINUX
167 /* Set the SELinux file creation context for the given file. */
168 static void set_file_creation_context (const char *outname, mode_t mode);
169 static void reset_file_creation_context (void);
170 #else
171 # define set_file_creation_context(_outname,_mode)
172 # define reset_file_creation_context()
173 #endif
176 /* External functions. */
177 #include <programs/xmalloc.h>
181 main (int argc, char *argv[])
183 const char *input_name;
184 FILE *input_file;
185 int remaining;
186 int mode = 0644;
188 /* Set locale via LC_ALL. */
189 setlocale (LC_ALL, "");
191 /* Set the text message domain. */
192 textdomain (_libc_intl_domainname);
194 /* Initialize local variables. */
195 input_name = NULL;
197 /* Parse and process arguments. */
198 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
200 /* Determine file names. */
201 if (do_undo || output_name != NULL)
203 if (remaining + 1 != argc)
205 wrong_arguments:
206 error (0, 0, gettext ("wrong number of arguments"));
207 argp_help (&argp, stdout, ARGP_HELP_SEE,
208 program_invocation_short_name);
209 exit (1);
211 input_name = argv[remaining];
213 else
215 if (remaining + 2 != argc)
216 goto wrong_arguments;
218 input_name = argv[remaining++];
219 output_name = argv[remaining];
222 /* Special handling if we are asked to print the database. */
223 if (do_undo)
225 int fd = open (input_name, O_RDONLY);
226 if (fd == -1)
227 error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
228 input_name);
230 int status = print_database (fd);
232 close (fd);
234 return status;
237 /* Open input file. */
238 if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
239 input_file = stdin;
240 else
242 struct stat64 st;
244 input_file = fopen64 (input_name, "r");
245 if (input_file == NULL)
246 error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
247 input_name);
249 /* Get the access rights from the source file. The output file should
250 have the same. */
251 if (fstat64 (fileno (input_file), &st) >= 0)
252 mode = st.st_mode & ACCESSPERMS;
255 /* Start the real work. */
256 int status = process_input (input_file, input_name, to_lowercase, be_quiet);
258 /* Close files. */
259 if (input_file != stdin)
260 fclose (input_file);
262 /* No need to continue when we did not read the file successfully. */
263 if (status != EXIT_SUCCESS)
264 return status;
266 /* Bail out if nothing is to be done. */
267 if (!any_dbentry)
269 if (be_quiet)
270 return EXIT_SUCCESS;
271 else
272 error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
275 /* Compute hash and string tables. */
276 compute_tables ();
278 /* Open output file. This must not be standard output so we don't
279 handle "-" and "/dev/stdout" special. */
280 char *tmp_output_name;
281 if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
282 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
284 set_file_creation_context (output_name, mode);
285 int fd = mkstemp (tmp_output_name);
286 reset_file_creation_context ();
287 if (fd == -1)
288 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
290 status = write_output (fd);
292 if (status == EXIT_SUCCESS)
294 struct stat64 st;
296 if (fstat64 (fd, &st) == 0)
298 if ((st.st_mode & ACCESSPERMS) != mode)
299 /* We ignore problems with changing the mode. */
300 fchmod (fd, mode);
302 else
304 error (0, errno, gettext ("cannot stat newly created file"));
305 status = EXIT_FAILURE;
309 close (fd);
311 if (status == EXIT_SUCCESS)
313 if (rename (tmp_output_name, output_name) != 0)
315 error (0, errno, gettext ("cannot rename temporary file"));
316 status = EXIT_FAILURE;
317 goto do_unlink;
320 else
321 do_unlink:
322 unlink (tmp_output_name);
324 return status;
328 /* Handle program arguments. */
329 static error_t
330 parse_opt (int key, char *arg, struct argp_state *state)
332 struct db_option *newp;
334 switch (key)
336 case 'f':
337 to_lowercase = 1;
338 break;
339 case 'o':
340 output_name = arg;
341 break;
342 case 'q':
343 be_quiet = 1;
344 break;
345 case 'u':
346 do_undo = 1;
347 break;
348 case 'g':
349 newp = xmalloc (sizeof (*newp));
350 newp->dbid = arg[0];
351 newp->next = db_options;
352 db_options = newp;
353 break;
354 default:
355 return ARGP_ERR_UNKNOWN;
357 return 0;
361 static char *
362 more_help (int key, const char *text, void *input)
364 char *tp = NULL;
365 switch (key)
367 case ARGP_KEY_HELP_EXTRA:
368 /* We print some extra information. */
369 if (asprintf (&tp, gettext ("\
370 For bug reporting instructions, please see:\n\
371 %s.\n"), REPORT_BUGS_TO) < 0)
372 return NULL;
373 return tp;
374 default:
375 break;
377 return (char *) text;
380 /* Print the version information. */
381 static void
382 print_version (FILE *stream, struct argp_state *state)
384 fprintf (stream, "makedb %s%s\n", PKGVERSION, VERSION);
385 fprintf (stream, gettext ("\
386 Copyright (C) %s Free Software Foundation, Inc.\n\
387 This is free software; see the source for copying conditions. There is NO\n\
388 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
389 "), "2022");
390 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
394 static int
395 dbentry_compare (const void *p1, const void *p2)
397 const struct dbentry *d1 = (const struct dbentry *) p1;
398 const struct dbentry *d2 = (const struct dbentry *) p2;
400 if (d1->hashval != d2->hashval)
401 return d1->hashval < d2->hashval ? -1 : 1;
403 return strcmp (d1->str, d2->str);
407 static int
408 valstr_compare (const void *p1, const void *p2)
410 const struct valstrentry *d1 = (const struct valstrentry *) p1;
411 const struct valstrentry *d2 = (const struct valstrentry *) p2;
413 return strcmp (d1->str, d2->str);
417 static int
418 process_input (FILE *input, const char *inname, int to_lowercase, int be_quiet)
420 char *line;
421 size_t linelen;
422 int status;
423 size_t linenr;
425 line = NULL;
426 linelen = 0;
427 status = EXIT_SUCCESS;
428 linenr = 0;
430 struct database *last_database = NULL;
432 while (!feof_unlocked (input))
434 ssize_t n = getline (&line, &linelen, input);
435 if (n < 0)
436 /* This means end of file or some bug. */
437 break;
438 if (n == 0)
439 /* Short read. Probably interrupted system call. */
440 continue;
442 ++linenr;
444 if (line[n - 1] == '\n')
445 /* Remove trailing newline. */
446 line[--n] = '\0';
448 char *cp = line;
449 while (isspace (*cp))
450 ++cp;
452 if (*cp == '#' || *cp == '\0')
453 /* First non-space character in line '#': it's a comment.
454 Also go to the next line if it is empty except for whitespaces. */
455 continue;
457 /* Skip over the character indicating the database so that it is not
458 affected by TO_LOWERCASE. */
459 char *key = cp++;
460 while (*cp != '\0' && !isspace (*cp))
462 if (to_lowercase)
463 *cp = tolower (*cp);
464 ++cp;
467 if (*cp == '\0')
468 /* It's a line without a value field. */
469 continue;
471 *cp++ = '\0';
472 size_t keylen = cp - key;
474 while (isspace (*cp))
475 ++cp;
477 char *data = cp;
478 size_t datalen = (&line[n] - cp) + 1;
480 /* Find the database. */
481 if (last_database == NULL || last_database->dbid != key[0])
483 last_database = databases;
484 while (last_database != NULL && last_database->dbid != key[0])
485 last_database = last_database->next;
487 if (last_database == NULL)
489 last_database = xmalloc (sizeof (*last_database));
490 last_database->dbid = key[0];
491 last_database->extra_string = false;
492 last_database->next = databases;
493 last_database->entries = NULL;
494 last_database->nentries = 0;
495 last_database->keystrlen = 0;
496 databases = last_database;
498 struct db_option *runp = db_options;
499 while (runp != NULL)
500 if (runp->dbid == key[0])
502 last_database->extra_string = true;
503 break;
505 else
506 runp = runp->next;
510 /* Skip the database selector. */
511 ++key;
512 --keylen;
514 /* Store the data. */
515 struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
516 + datalen);
517 if (last_database->extra_string)
518 nentry->idx = extrastrlen;
519 else
520 nentry->idx = valstrlen;
521 nentry->extra_string = last_database->extra_string;
522 memcpy (nentry->str, data, datalen);
524 struct valstrentry **fdata = tsearch (nentry, &valstrtree,
525 valstr_compare);
526 if (fdata == NULL)
527 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
529 if (*fdata != nentry)
531 /* We can reuse a string. */
532 free (nentry);
533 nentry = *fdata;
535 else
536 if (last_database->extra_string)
537 extrastrlen += datalen;
538 else
539 valstrlen += datalen;
541 /* Store the key. */
542 struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
543 newp->validx = nentry->idx;
544 newp->hashval = __hash_string (key);
545 memcpy (newp->str, key, keylen);
547 struct dbentry **found = tsearch (newp, &last_database->entries,
548 dbentry_compare);
549 if (found == NULL)
550 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
552 if (*found != newp)
554 free (newp);
555 if (!be_quiet)
556 error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
557 continue;
560 ++last_database->nentries;
561 last_database->keystrlen += keylen;
563 any_dbentry = true;
566 if (ferror_unlocked (input))
568 error (0, 0, gettext ("problems while reading `%s'"), inname);
569 status = EXIT_FAILURE;
572 return status;
576 static void
577 copy_valstr (const void *nodep, const VISIT which, const int depth)
579 if (which != leaf && which != postorder)
580 return;
582 const struct valstrentry *p = *(const struct valstrentry **) nodep;
584 strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str);
588 /* Determine if the candidate is prime by using a modified trial division
589 algorithm. The candidate must be both odd and greater than 4. */
590 static int
591 is_prime (size_t candidate)
593 size_t divn = 3;
594 size_t sq = divn * divn;
596 assert (candidate > 4 && candidate % 2 != 0);
598 while (sq < candidate && candidate % divn != 0)
600 ++divn;
601 sq += 4 * divn;
602 ++divn;
605 return candidate % divn != 0;
609 static size_t
610 next_prime (size_t seed)
612 /* Make sure that we're always greater than 4. */
613 seed = (seed + 4) | 1;
615 while (!is_prime (seed))
616 seed += 2;
618 return seed;
621 static size_t max_chainlength;
622 static char *wp;
623 static size_t nhashentries;
624 static bool copy_string;
626 void add_key(const void *nodep, VISIT which, void *arg)
628 if (which != leaf && which != postorder)
629 return;
631 const struct database *db = (const struct database *) arg;
632 const struct dbentry *dbe = *(const struct dbentry **) nodep;
634 ptrdiff_t stridx;
635 if (copy_string)
637 stridx = wp - db->keystrtab;
638 wp = stpcpy (wp, dbe->str) + 1;
640 else
641 stridx = 0;
643 size_t hidx = dbe->hashval % nhashentries;
644 size_t hval2 = 1 + dbe->hashval % (nhashentries - 2);
645 size_t chainlength = 0;
647 while (db->hashtable[hidx] != ~((stridx_t) 0))
649 ++chainlength;
650 if ((hidx += hval2) >= nhashentries)
651 hidx -= nhashentries;
654 db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0)
655 + dbe->validx);
656 db->keyidxtab[hidx] = stridx;
658 max_chainlength = MAX (max_chainlength, chainlength);
661 static void
662 compute_tables (void)
664 valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t)));
665 while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0)
666 valstrtab[valstrlen++] = '\0';
667 twalk (valstrtree, copy_valstr);
669 static struct database *db;
670 for (db = databases; db != NULL; db = db->next)
671 if (db->nentries != 0)
673 ++ndatabases;
675 /* We simply use an odd number large than twice the number of
676 elements to store in the hash table for the size. This gives
677 enough efficiency. */
678 #define TEST_RANGE 30
679 size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE
680 ? db->nentries
681 : db->nentries * 2 - TEST_RANGE);
682 size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4);
683 size_t nhashentries_best = nhashentries_min;
684 size_t chainlength_best = db->nentries;
686 db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t)
687 + db->keystrlen);
688 db->keyidxtab = db->hashtable + nhashentries_max;
689 db->keystrtab = (char *) (db->keyidxtab + nhashentries_max);
691 copy_string = false;
692 nhashentries = nhashentries_min;
693 for (size_t cnt = 0; cnt < TEST_RANGE; ++cnt)
695 memset (db->hashtable, '\xff', nhashentries * sizeof (stridx_t));
697 max_chainlength = 0;
698 wp = db->keystrtab;
700 twalk_r (db->entries, add_key, db);
702 if (max_chainlength == 0)
704 /* No need to look further, this is as good as it gets. */
705 nhashentries_best = nhashentries;
706 break;
709 if (max_chainlength < chainlength_best)
711 chainlength_best = max_chainlength;
712 nhashentries_best = nhashentries;
715 nhashentries = next_prime (nhashentries + 1);
716 if (nhashentries > nhashentries_max)
717 break;
720 /* Recompute the best table again, this time fill in the strings. */
721 nhashentries = nhashentries_best;
722 memset (db->hashtable, '\xff',
723 2 * nhashentries_max * sizeof (stridx_t));
724 copy_string = true;
725 wp = db->keystrtab;
727 twalk_r (db->entries, add_key, db);
729 db->nhashentries = nhashentries_best;
730 nhashentries_total += nhashentries_best;
735 static int
736 write_output (int fd)
738 struct nss_db_header *header;
739 uint64_t file_offset = (sizeof (struct nss_db_header)
740 + (ndatabases * sizeof (header->dbs[0])));
741 header = alloca (file_offset);
743 header->magic = NSS_DB_MAGIC;
744 header->ndbs = ndatabases;
745 header->valstroffset = file_offset;
746 header->valstrlen = valstrlen;
748 size_t filled_dbs = 0;
749 size_t iov_nelts = 2 + ndatabases * 3;
750 struct iovec iov[iov_nelts];
751 iov[0].iov_base = header;
752 iov[0].iov_len = file_offset;
754 iov[1].iov_base = valstrtab;
755 iov[1].iov_len = valstrlen + extrastrlen;
756 file_offset += iov[1].iov_len;
758 size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t);
759 for (struct database *db = databases; db != NULL; db = db->next)
760 if (db->entries != NULL)
762 assert (file_offset % sizeof (stridx_t) == 0);
763 assert (filled_dbs < ndatabases);
765 header->dbs[filled_dbs].id = db->dbid;
766 memset (header->dbs[filled_dbs].pad, '\0',
767 sizeof (header->dbs[0].pad));
768 header->dbs[filled_dbs].hashsize = db->nhashentries;
770 iov[2 + filled_dbs].iov_base = db->hashtable;
771 iov[2 + filled_dbs].iov_len = db->nhashentries * sizeof (stridx_t);
772 header->dbs[filled_dbs].hashoffset = file_offset;
773 file_offset += iov[2 + filled_dbs].iov_len;
775 iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
776 iov[2 + ndatabases + filled_dbs * 2].iov_len
777 = db->nhashentries * sizeof (stridx_t);
778 header->dbs[filled_dbs].keyidxoffset = keydataoffset;
779 keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
781 iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab;
782 iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen;
783 header->dbs[filled_dbs].keystroffset = keydataoffset;
784 keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len;
786 ++filled_dbs;
789 assert (filled_dbs == ndatabases);
790 assert (file_offset == (iov[0].iov_len + iov[1].iov_len
791 + nhashentries_total * sizeof (stridx_t)));
792 header->allocate = file_offset;
794 #if __GNUC_PREREQ (10, 0) && !__GNUC_PREREQ (11, 0)
795 DIAG_PUSH_NEEDS_COMMENT;
796 /* Avoid GCC 10 false positive warning: specified size exceeds maximum
797 object size. */
798 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wstringop-overflow");
799 #endif
801 assert (iov_nelts <= INT_MAX);
802 if (writev (fd, iov, iov_nelts) != keydataoffset)
804 error (0, errno, gettext ("failed to write new database file"));
805 return EXIT_FAILURE;
808 #if __GNUC_PREREQ (10, 0) && !__GNUC_PREREQ (11, 0)
809 DIAG_POP_NEEDS_COMMENT;
810 #endif
812 return EXIT_SUCCESS;
816 static int
817 print_database (int fd)
819 struct stat64 st;
820 if (fstat64 (fd, &st) != 0)
821 error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
823 const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
824 MAP_PRIVATE|MAP_POPULATE, fd, 0);
825 if (header == MAP_FAILED)
826 error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
828 if (header->magic != NSS_DB_MAGIC)
829 error (EXIT_FAILURE, 0, gettext ("file not a database file"));
831 const char *valstrtab = (const char *) header + header->valstroffset;
833 for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
835 const stridx_t *stridxtab
836 = ((const stridx_t *) ((const char *) header
837 + header->dbs[dbidx].keyidxoffset));
838 const char *keystrtab
839 = (const char *) header + header->dbs[dbidx].keystroffset;
840 const stridx_t *hashtab
841 = (const stridx_t *) ((const char *) header
842 + header->dbs[dbidx].hashoffset);
844 for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
845 if (hashtab[hidx] != ~((stridx_t) 0))
846 printf ("%c%s %s\n",
847 header->dbs[dbidx].id,
848 keystrtab + stridxtab[hidx],
849 valstrtab + hashtab[hidx]);
852 return EXIT_SUCCESS;
856 #ifdef HAVE_SELINUX
858 /* security_context_t and matchpathcon (along with several other symbols) were
859 marked as deprecated by the SELinux API starting from version 3.1. We use
860 them here, but should eventually switch to the newer API. */
861 DIAG_PUSH_NEEDS_COMMENT
862 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
864 static void
865 set_file_creation_context (const char *outname, mode_t mode)
867 static int enabled;
868 static int enforcing;
869 security_context_t ctx;
871 /* Check if SELinux is enabled, and remember. */
872 if (enabled == 0)
873 enabled = is_selinux_enabled () ? 1 : -1;
874 if (enabled < 0)
875 return;
877 /* Check if SELinux is enforcing, and remember. */
878 if (enforcing == 0)
879 enforcing = security_getenforce () ? 1 : -1;
881 /* Determine the context which the file should have. */
882 ctx = NULL;
883 if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
885 if (setfscreatecon (ctx) != 0)
886 error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
887 gettext ("cannot set file creation context for `%s'"),
888 outname);
890 freecon (ctx);
893 DIAG_POP_NEEDS_COMMENT
895 static void
896 reset_file_creation_context (void)
898 setfscreatecon (NULL);
900 #endif