nis: Fix leak on realloc failure in nis_getnames [BZ #28150]
[glibc.git] / nss / makedb.c
blob8690e11e82e2486e730961c8ae49924b04f55c8b
1 /* Create simple DB database from textual input.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
20 #include <argp.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <error.h>
25 #include <fcntl.h>
26 #include <inttypes.h>
27 #include <libintl.h>
28 #include <locale.h>
29 #include <search.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <stdint.h>
36 #include <sys/mman.h>
37 #include <sys/param.h>
38 #include <sys/stat.h>
39 #include <sys/uio.h>
40 #include "nss_db/nss_db.h"
41 #include <libc-diag.h>
43 /* Get libc version number. */
44 #include "../version.h"
46 /* The hashing function we use. */
47 #include "../intl/hash-string.h"
49 /* SELinux support. */
50 #ifdef HAVE_SELINUX
51 # include <selinux/selinux.h>
52 #endif
54 #ifndef MAP_POPULATE
55 # define MAP_POPULATE 0
56 #endif
58 #define PACKAGE _libc_intl_domainname
60 /* List of data bases. */
61 struct database
63 char dbid;
64 bool extra_string;
65 struct database *next;
66 void *entries;
67 size_t nentries;
68 size_t nhashentries;
69 stridx_t *hashtable;
70 size_t keystrlen;
71 stridx_t *keyidxtab;
72 char *keystrtab;
73 } *databases;
74 static size_t ndatabases;
75 static size_t nhashentries_total;
76 static size_t valstrlen;
77 static void *valstrtree;
78 static char *valstrtab;
79 static size_t extrastrlen;
81 /* Database entry. */
82 struct dbentry
84 stridx_t validx;
85 uint32_t hashval;
86 char str[0];
89 /* Stored string entry. */
90 struct valstrentry
92 stridx_t idx;
93 bool extra_string;
94 char str[0];
98 /* True if any entry has been added. */
99 static bool any_dbentry;
101 /* If non-zero convert key to lower case. */
102 static int to_lowercase;
104 /* If non-zero print content of input file, one entry per line. */
105 static int do_undo;
107 /* If non-zero do not print informational messages. */
108 static int be_quiet;
110 /* Name of output file. */
111 static const char *output_name;
113 /* Name and version of program. */
114 static void print_version (FILE *stream, struct argp_state *state);
115 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
117 /* Definitions of arguments for argp functions. */
118 static const struct argp_option options[] =
120 { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
121 { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
122 { "quiet", 'q', NULL, 0,
123 N_("Do not print messages while building database") },
124 { "undo", 'u', NULL, 0,
125 N_("Print content of database file, one entry a line") },
126 { "generated", 'g', N_("CHAR"), 0,
127 N_("Generated line not part of iteration") },
128 { NULL, 0, NULL, 0, NULL }
131 /* Short description of program. */
132 static const char doc[] = N_("Create simple database from textual input.");
134 /* Strings for arguments in help texts. */
135 static const char args_doc[] = N_("\
136 INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
138 /* Prototype for option handler. */
139 static error_t parse_opt (int key, char *arg, struct argp_state *state);
141 /* Function to print some extra text in the help message. */
142 static char *more_help (int key, const char *text, void *input);
144 /* Data structure to communicate with argp functions. */
145 static struct argp argp =
147 options, parse_opt, args_doc, doc, NULL, more_help
151 /* List of databases which are not part of the iteration table. */
152 static struct db_option
154 char dbid;
155 struct db_option *next;
156 } *db_options;
159 /* Prototypes for local functions. */
160 static int process_input (FILE *input, const char *inname,
161 int to_lowercase, int be_quiet);
162 static int print_database (int fd);
163 static void compute_tables (void);
164 static int write_output (int fd);
166 /* SELinux support. */
167 #ifdef HAVE_SELINUX
168 /* Set the SELinux file creation context for the given file. */
169 static void set_file_creation_context (const char *outname, mode_t mode);
170 static void reset_file_creation_context (void);
171 #else
172 # define set_file_creation_context(_outname,_mode)
173 # define reset_file_creation_context()
174 #endif
177 /* External functions. */
178 #include <programs/xmalloc.h>
182 main (int argc, char *argv[])
184 const char *input_name;
185 FILE *input_file;
186 int remaining;
187 int mode = 0644;
189 /* Set locale via LC_ALL. */
190 setlocale (LC_ALL, "");
192 /* Set the text message domain. */
193 textdomain (_libc_intl_domainname);
195 /* Initialize local variables. */
196 input_name = NULL;
198 /* Parse and process arguments. */
199 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
201 /* Determine file names. */
202 if (do_undo || output_name != NULL)
204 if (remaining + 1 != argc)
206 wrong_arguments:
207 error (0, 0, gettext ("wrong number of arguments"));
208 argp_help (&argp, stdout, ARGP_HELP_SEE,
209 program_invocation_short_name);
210 exit (1);
212 input_name = argv[remaining];
214 else
216 if (remaining + 2 != argc)
217 goto wrong_arguments;
219 input_name = argv[remaining++];
220 output_name = argv[remaining];
223 /* Special handling if we are asked to print the database. */
224 if (do_undo)
226 int fd = open (input_name, O_RDONLY);
227 if (fd == -1)
228 error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
229 input_name);
231 int status = print_database (fd);
233 close (fd);
235 return status;
238 /* Open input file. */
239 if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
240 input_file = stdin;
241 else
243 struct stat64 st;
245 input_file = fopen64 (input_name, "r");
246 if (input_file == NULL)
247 error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
248 input_name);
250 /* Get the access rights from the source file. The output file should
251 have the same. */
252 if (fstat64 (fileno (input_file), &st) >= 0)
253 mode = st.st_mode & ACCESSPERMS;
256 /* Start the real work. */
257 int status = process_input (input_file, input_name, to_lowercase, be_quiet);
259 /* Close files. */
260 if (input_file != stdin)
261 fclose (input_file);
263 /* No need to continue when we did not read the file successfully. */
264 if (status != EXIT_SUCCESS)
265 return status;
267 /* Bail out if nothing is to be done. */
268 if (!any_dbentry)
270 if (be_quiet)
271 return EXIT_SUCCESS;
272 else
273 error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
276 /* Compute hash and string tables. */
277 compute_tables ();
279 /* Open output file. This must not be standard output so we don't
280 handle "-" and "/dev/stdout" special. */
281 char *tmp_output_name;
282 if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
283 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
285 set_file_creation_context (output_name, mode);
286 int fd = mkstemp (tmp_output_name);
287 reset_file_creation_context ();
288 if (fd == -1)
289 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
291 status = write_output (fd);
293 if (status == EXIT_SUCCESS)
295 struct stat64 st;
297 if (fstat64 (fd, &st) == 0)
299 if ((st.st_mode & ACCESSPERMS) != mode)
300 /* We ignore problems with changing the mode. */
301 fchmod (fd, mode);
303 else
305 error (0, errno, gettext ("cannot stat newly created file"));
306 status = EXIT_FAILURE;
310 close (fd);
312 if (status == EXIT_SUCCESS)
314 if (rename (tmp_output_name, output_name) != 0)
316 error (0, errno, gettext ("cannot rename temporary file"));
317 status = EXIT_FAILURE;
318 goto do_unlink;
321 else
322 do_unlink:
323 unlink (tmp_output_name);
325 return status;
329 /* Handle program arguments. */
330 static error_t
331 parse_opt (int key, char *arg, struct argp_state *state)
333 struct db_option *newp;
335 switch (key)
337 case 'f':
338 to_lowercase = 1;
339 break;
340 case 'o':
341 output_name = arg;
342 break;
343 case 'q':
344 be_quiet = 1;
345 break;
346 case 'u':
347 do_undo = 1;
348 break;
349 case 'g':
350 newp = xmalloc (sizeof (*newp));
351 newp->dbid = arg[0];
352 newp->next = db_options;
353 db_options = newp;
354 break;
355 default:
356 return ARGP_ERR_UNKNOWN;
358 return 0;
362 static char *
363 more_help (int key, const char *text, void *input)
365 char *tp = NULL;
366 switch (key)
368 case ARGP_KEY_HELP_EXTRA:
369 /* We print some extra information. */
370 if (asprintf (&tp, gettext ("\
371 For bug reporting instructions, please see:\n\
372 %s.\n"), REPORT_BUGS_TO) < 0)
373 return NULL;
374 return tp;
375 default:
376 break;
378 return (char *) text;
381 /* Print the version information. */
382 static void
383 print_version (FILE *stream, struct argp_state *state)
385 fprintf (stream, "makedb %s%s\n", PKGVERSION, VERSION);
386 fprintf (stream, gettext ("\
387 Copyright (C) %s Free Software Foundation, Inc.\n\
388 This is free software; see the source for copying conditions. There is NO\n\
389 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
390 "), "2021");
391 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
395 static int
396 dbentry_compare (const void *p1, const void *p2)
398 const struct dbentry *d1 = (const struct dbentry *) p1;
399 const struct dbentry *d2 = (const struct dbentry *) p2;
401 if (d1->hashval != d2->hashval)
402 return d1->hashval < d2->hashval ? -1 : 1;
404 return strcmp (d1->str, d2->str);
408 static int
409 valstr_compare (const void *p1, const void *p2)
411 const struct valstrentry *d1 = (const struct valstrentry *) p1;
412 const struct valstrentry *d2 = (const struct valstrentry *) p2;
414 return strcmp (d1->str, d2->str);
418 static int
419 process_input (FILE *input, const char *inname, int to_lowercase, int be_quiet)
421 char *line;
422 size_t linelen;
423 int status;
424 size_t linenr;
426 line = NULL;
427 linelen = 0;
428 status = EXIT_SUCCESS;
429 linenr = 0;
431 struct database *last_database = NULL;
433 while (!feof_unlocked (input))
435 ssize_t n = getline (&line, &linelen, input);
436 if (n < 0)
437 /* This means end of file or some bug. */
438 break;
439 if (n == 0)
440 /* Short read. Probably interrupted system call. */
441 continue;
443 ++linenr;
445 if (line[n - 1] == '\n')
446 /* Remove trailing newline. */
447 line[--n] = '\0';
449 char *cp = line;
450 while (isspace (*cp))
451 ++cp;
453 if (*cp == '#' || *cp == '\0')
454 /* First non-space character in line '#': it's a comment.
455 Also go to the next line if it is empty except for whitespaces. */
456 continue;
458 /* Skip over the character indicating the database so that it is not
459 affected by TO_LOWERCASE. */
460 char *key = cp++;
461 while (*cp != '\0' && !isspace (*cp))
463 if (to_lowercase)
464 *cp = tolower (*cp);
465 ++cp;
468 if (*cp == '\0')
469 /* It's a line without a value field. */
470 continue;
472 *cp++ = '\0';
473 size_t keylen = cp - key;
475 while (isspace (*cp))
476 ++cp;
478 char *data = cp;
479 size_t datalen = (&line[n] - cp) + 1;
481 /* Find the database. */
482 if (last_database == NULL || last_database->dbid != key[0])
484 last_database = databases;
485 while (last_database != NULL && last_database->dbid != key[0])
486 last_database = last_database->next;
488 if (last_database == NULL)
490 last_database = xmalloc (sizeof (*last_database));
491 last_database->dbid = key[0];
492 last_database->extra_string = false;
493 last_database->next = databases;
494 last_database->entries = NULL;
495 last_database->nentries = 0;
496 last_database->keystrlen = 0;
497 databases = last_database;
499 struct db_option *runp = db_options;
500 while (runp != NULL)
501 if (runp->dbid == key[0])
503 last_database->extra_string = true;
504 break;
506 else
507 runp = runp->next;
511 /* Skip the database selector. */
512 ++key;
513 --keylen;
515 /* Store the data. */
516 struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
517 + datalen);
518 if (last_database->extra_string)
519 nentry->idx = extrastrlen;
520 else
521 nentry->idx = valstrlen;
522 nentry->extra_string = last_database->extra_string;
523 memcpy (nentry->str, data, datalen);
525 struct valstrentry **fdata = tsearch (nentry, &valstrtree,
526 valstr_compare);
527 if (fdata == NULL)
528 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
530 if (*fdata != nentry)
532 /* We can reuse a string. */
533 free (nentry);
534 nentry = *fdata;
536 else
537 if (last_database->extra_string)
538 extrastrlen += datalen;
539 else
540 valstrlen += datalen;
542 /* Store the key. */
543 struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
544 newp->validx = nentry->idx;
545 newp->hashval = __hash_string (key);
546 memcpy (newp->str, key, keylen);
548 struct dbentry **found = tsearch (newp, &last_database->entries,
549 dbentry_compare);
550 if (found == NULL)
551 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
553 if (*found != newp)
555 free (newp);
556 if (!be_quiet)
557 error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
558 continue;
561 ++last_database->nentries;
562 last_database->keystrlen += keylen;
564 any_dbentry = true;
567 if (ferror_unlocked (input))
569 error (0, 0, gettext ("problems while reading `%s'"), inname);
570 status = EXIT_FAILURE;
573 return status;
577 static void
578 copy_valstr (const void *nodep, const VISIT which, const int depth)
580 if (which != leaf && which != postorder)
581 return;
583 const struct valstrentry *p = *(const struct valstrentry **) nodep;
585 strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str);
589 /* Determine if the candidate is prime by using a modified trial division
590 algorithm. The candidate must be both odd and greater than 4. */
591 static int
592 is_prime (size_t candidate)
594 size_t divn = 3;
595 size_t sq = divn * divn;
597 assert (candidate > 4 && candidate % 2 != 0);
599 while (sq < candidate && candidate % divn != 0)
601 ++divn;
602 sq += 4 * divn;
603 ++divn;
606 return candidate % divn != 0;
610 static size_t
611 next_prime (size_t seed)
613 /* Make sure that we're always greater than 4. */
614 seed = (seed + 4) | 1;
616 while (!is_prime (seed))
617 seed += 2;
619 return seed;
623 static void
624 compute_tables (void)
626 valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t)));
627 while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0)
628 valstrtab[valstrlen++] = '\0';
629 twalk (valstrtree, copy_valstr);
631 static struct database *db;
632 for (db = databases; db != NULL; db = db->next)
633 if (db->nentries != 0)
635 ++ndatabases;
637 /* We simply use an odd number large than twice the number of
638 elements to store in the hash table for the size. This gives
639 enough efficiency. */
640 #define TEST_RANGE 30
641 size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE
642 ? db->nentries
643 : db->nentries * 2 - TEST_RANGE);
644 size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4);
645 size_t nhashentries_best = nhashentries_min;
646 size_t chainlength_best = db->nentries;
648 db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t)
649 + db->keystrlen);
650 db->keyidxtab = db->hashtable + nhashentries_max;
651 db->keystrtab = (char *) (db->keyidxtab + nhashentries_max);
653 static size_t max_chainlength;
654 static char *wp;
655 static size_t nhashentries;
656 static bool copy_string;
658 void add_key(const void *nodep, const VISIT which, const int depth)
660 if (which != leaf && which != postorder)
661 return;
663 const struct dbentry *dbe = *(const struct dbentry **) nodep;
665 ptrdiff_t stridx;
666 if (copy_string)
668 stridx = wp - db->keystrtab;
669 wp = stpcpy (wp, dbe->str) + 1;
671 else
672 stridx = 0;
674 size_t hidx = dbe->hashval % nhashentries;
675 size_t hval2 = 1 + dbe->hashval % (nhashentries - 2);
676 size_t chainlength = 0;
678 while (db->hashtable[hidx] != ~((stridx_t) 0))
680 ++chainlength;
681 if ((hidx += hval2) >= nhashentries)
682 hidx -= nhashentries;
685 db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0)
686 + dbe->validx);
687 db->keyidxtab[hidx] = stridx;
689 max_chainlength = MAX (max_chainlength, chainlength);
692 copy_string = false;
693 nhashentries = nhashentries_min;
694 for (size_t cnt = 0; cnt < TEST_RANGE; ++cnt)
696 memset (db->hashtable, '\xff', nhashentries * sizeof (stridx_t));
698 max_chainlength = 0;
699 wp = db->keystrtab;
701 twalk (db->entries, add_key);
703 if (max_chainlength == 0)
705 /* No need to look further, this is as good as it gets. */
706 nhashentries_best = nhashentries;
707 break;
710 if (max_chainlength < chainlength_best)
712 chainlength_best = max_chainlength;
713 nhashentries_best = nhashentries;
716 nhashentries = next_prime (nhashentries + 1);
717 if (nhashentries > nhashentries_max)
718 break;
721 /* Recompute the best table again, this time fill in the strings. */
722 nhashentries = nhashentries_best;
723 memset (db->hashtable, '\xff',
724 2 * nhashentries_max * sizeof (stridx_t));
725 copy_string = true;
726 wp = db->keystrtab;
728 twalk (db->entries, add_key);
730 db->nhashentries = nhashentries_best;
731 nhashentries_total += nhashentries_best;
736 static int
737 write_output (int fd)
739 struct nss_db_header *header;
740 uint64_t file_offset = (sizeof (struct nss_db_header)
741 + (ndatabases * sizeof (header->dbs[0])));
742 header = alloca (file_offset);
744 header->magic = NSS_DB_MAGIC;
745 header->ndbs = ndatabases;
746 header->valstroffset = file_offset;
747 header->valstrlen = valstrlen;
749 size_t filled_dbs = 0;
750 size_t iov_nelts = 2 + ndatabases * 3;
751 struct iovec iov[iov_nelts];
752 iov[0].iov_base = header;
753 iov[0].iov_len = file_offset;
755 iov[1].iov_base = valstrtab;
756 iov[1].iov_len = valstrlen + extrastrlen;
757 file_offset += iov[1].iov_len;
759 size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t);
760 for (struct database *db = databases; db != NULL; db = db->next)
761 if (db->entries != NULL)
763 assert (file_offset % sizeof (stridx_t) == 0);
764 assert (filled_dbs < ndatabases);
766 header->dbs[filled_dbs].id = db->dbid;
767 memset (header->dbs[filled_dbs].pad, '\0',
768 sizeof (header->dbs[0].pad));
769 header->dbs[filled_dbs].hashsize = db->nhashentries;
771 iov[2 + filled_dbs].iov_base = db->hashtable;
772 iov[2 + filled_dbs].iov_len = db->nhashentries * sizeof (stridx_t);
773 header->dbs[filled_dbs].hashoffset = file_offset;
774 file_offset += iov[2 + filled_dbs].iov_len;
776 iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
777 iov[2 + ndatabases + filled_dbs * 2].iov_len
778 = db->nhashentries * sizeof (stridx_t);
779 header->dbs[filled_dbs].keyidxoffset = keydataoffset;
780 keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
782 iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab;
783 iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen;
784 header->dbs[filled_dbs].keystroffset = keydataoffset;
785 keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len;
787 ++filled_dbs;
790 assert (filled_dbs == ndatabases);
791 assert (file_offset == (iov[0].iov_len + iov[1].iov_len
792 + nhashentries_total * sizeof (stridx_t)));
793 header->allocate = file_offset;
795 #if __GNUC_PREREQ (10, 0) && !__GNUC_PREREQ (11, 0)
796 DIAG_PUSH_NEEDS_COMMENT;
797 /* Avoid GCC 10 false positive warning: specified size exceeds maximum
798 object size. */
799 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wstringop-overflow");
800 #endif
802 assert (iov_nelts <= INT_MAX);
803 if (writev (fd, iov, iov_nelts) != keydataoffset)
805 error (0, errno, gettext ("failed to write new database file"));
806 return EXIT_FAILURE;
809 #if __GNUC_PREREQ (10, 0) && !__GNUC_PREREQ (11, 0)
810 DIAG_POP_NEEDS_COMMENT;
811 #endif
813 return EXIT_SUCCESS;
817 static int
818 print_database (int fd)
820 struct stat64 st;
821 if (fstat64 (fd, &st) != 0)
822 error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
824 const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
825 MAP_PRIVATE|MAP_POPULATE, fd, 0);
826 if (header == MAP_FAILED)
827 error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
829 if (header->magic != NSS_DB_MAGIC)
830 error (EXIT_FAILURE, 0, gettext ("file not a database file"));
832 const char *valstrtab = (const char *) header + header->valstroffset;
834 for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
836 const stridx_t *stridxtab
837 = ((const stridx_t *) ((const char *) header
838 + header->dbs[dbidx].keyidxoffset));
839 const char *keystrtab
840 = (const char *) header + header->dbs[dbidx].keystroffset;
841 const stridx_t *hashtab
842 = (const stridx_t *) ((const char *) header
843 + header->dbs[dbidx].hashoffset);
845 for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
846 if (hashtab[hidx] != ~((stridx_t) 0))
847 printf ("%c%s %s\n",
848 header->dbs[dbidx].id,
849 keystrtab + stridxtab[hidx],
850 valstrtab + hashtab[hidx]);
853 return EXIT_SUCCESS;
857 #ifdef HAVE_SELINUX
859 /* security_context_t and matchpathcon (along with several other symbols) were
860 marked as deprecated by the SELinux API starting from version 3.1. We use
861 them here, but should eventually switch to the newer API. */
862 DIAG_PUSH_NEEDS_COMMENT
863 DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
865 static void
866 set_file_creation_context (const char *outname, mode_t mode)
868 static int enabled;
869 static int enforcing;
870 security_context_t ctx;
872 /* Check if SELinux is enabled, and remember. */
873 if (enabled == 0)
874 enabled = is_selinux_enabled () ? 1 : -1;
875 if (enabled < 0)
876 return;
878 /* Check if SELinux is enforcing, and remember. */
879 if (enforcing == 0)
880 enforcing = security_getenforce () ? 1 : -1;
882 /* Determine the context which the file should have. */
883 ctx = NULL;
884 if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
886 if (setfscreatecon (ctx) != 0)
887 error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
888 gettext ("cannot set file creation context for `%s'"),
889 outname);
891 freecon (ctx);
894 DIAG_POP_NEEDS_COMMENT
896 static void
897 reset_file_creation_context (void)
899 setfscreatecon (NULL);
901 #endif