Imported Upstream version 4.4
[platform/upstream/make.git] / src / posixos.c
1 /* POSIX-based operating system interface for GNU Make.
2 Copyright (C) 2016-2022 Free Software Foundation, Inc.
3 This file is part of GNU Make.
4
5 GNU Make is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3 of the License, or (at your option) any later
8 version.
9
10 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program.  If not, see <https://www.gnu.org/licenses/>.  */
16
17 #include "makeint.h"
18
19 #include <stdio.h>
20
21 #ifdef HAVE_FCNTL_H
22 # include <fcntl.h>
23 # define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
24 #elif defined(HAVE_SYS_FILE_H)
25 # include <sys/file.h>
26 #endif
27
28 #if !defined(FD_OK)
29 # define FD_OK(_f) 1
30 #endif
31
32 #if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H)
33 # include <sys/select.h>
34 #endif
35
36 #include "debug.h"
37 #include "job.h"
38 #include "os.h"
39
40 #define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
41
42 unsigned int
43 check_io_state ()
44 {
45   static unsigned int state = IO_UNKNOWN;
46
47   /* We only need to compute this once per process.  */
48   if (state != IO_UNKNOWN)
49     return state;
50
51   if (STREAM_OK (stdin))
52     state |= IO_STDIN_OK;
53   if (STREAM_OK (stdout))
54     state |= IO_STDOUT_OK;
55   if (STREAM_OK (stderr))
56     state |= IO_STDERR_OK;
57
58   if (ALL_SET (state, IO_STDOUT_OK|IO_STDERR_OK))
59     {
60       struct stat stbuf_o, stbuf_e;
61
62       if (fstat (fileno (stdout), &stbuf_o) == 0
63           && fstat (fileno (stderr), &stbuf_e) == 0
64           && stbuf_o.st_dev == stbuf_e.st_dev
65           && stbuf_o.st_ino == stbuf_e.st_ino)
66         state |= IO_COMBINED_OUTERR;
67     }
68
69   return state;
70 }
71
72 #if defined(MAKE_JOBSERVER)
73
74 #define FIFO_PREFIX    "fifo:"
75
76 /* This section provides OS-specific functions to support the jobserver.  */
77
78 /* True if this is the root make instance.  */
79 static unsigned char job_root = 0;
80
81 /* These track the state of the jobserver pipe.  Passed to child instances.  */
82 static int job_fds[2] = { -1, -1 };
83
84 /* Used to signal read() that a SIGCHLD happened.  Always CLOEXEC.
85    If we use pselect() this will never be created and always -1.
86  */
87 static int job_rfd = -1;
88
89 /* Token written to the pipe (could be any character...)  */
90 static char token = '+';
91
92 /* The type of jobserver we're using.  */
93 enum js_type
94   {
95     js_none = 0,        /* No jobserver.  */
96     js_pipe,            /* Use a simple pipe as the jobserver.  */
97     js_fifo             /* Use a named pipe as the jobserver.  */
98   };
99
100 static enum js_type js_type = js_none;
101
102 /* The name of the named pipe (if used).  */
103 static char *fifo_name = NULL;
104
105 static int
106 make_job_rfd ()
107 {
108 #ifdef HAVE_PSELECT
109   /* Pretend we succeeded.  */
110   return 0;
111 #else
112   EINTRLOOP (job_rfd, dup (job_fds[0]));
113   if (job_rfd >= 0)
114     fd_noinherit (job_rfd);
115
116   return job_rfd;
117 #endif
118 }
119
120 static void
121 set_blocking (int fd, int blocking)
122 {
123   /* If we're not using pselect() don't change the blocking.  */
124 #ifdef HAVE_PSELECT
125   int flags;
126   EINTRLOOP (flags, fcntl (fd, F_GETFL));
127   if (flags >= 0)
128     {
129       int r;
130       flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
131       EINTRLOOP (r, fcntl (fd, F_SETFL, flags));
132       if (r < 0)
133         pfatal_with_name ("fcntl(O_NONBLOCK)");
134     }
135 #endif
136 }
137
138 unsigned int
139 jobserver_setup (int slots, const char *style)
140 {
141   int r;
142
143 #if HAVE_MKFIFO
144   if (style == NULL || strcmp (style, "fifo") == 0)
145     {
146   /* Unfortunately glibc warns about uses of mktemp even though we aren't
147      using it in dangerous way here.  So avoid this by generating our own
148      temporary file name.  */
149 # define  FNAME_PREFIX "GMfifo"
150       const char *tmpdir = get_tmpdir ();
151
152       fifo_name = xmalloc (strlen (tmpdir) + CSTRLEN (FNAME_PREFIX)
153                            + INTSTR_LENGTH + 2);
154       sprintf (fifo_name, "%s/" FNAME_PREFIX "%" MK_PRI64_PREFIX "d",
155                tmpdir, (long long)make_pid ());
156
157       EINTRLOOP (r, mkfifo (fifo_name, 0600));
158       if (r < 0)
159         {
160           perror_with_name("jobserver mkfifo: ", fifo_name);
161           free (fifo_name);
162           fifo_name = NULL;
163         }
164       else
165         {
166           /* We have to open the read side in non-blocking mode, else it will
167              hang until the write side is open.  */
168           EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY|O_NONBLOCK));
169           if (job_fds[0] < 0)
170             OSS (fatal, NILF, _("Cannot open jobserver %s: %s"),
171                  fifo_name, strerror (errno));
172
173           EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
174           if (job_fds[0] < 0)
175             OSS (fatal, NILF, _("Cannot open jobserver %s: %s"),
176                  fifo_name, strerror (errno));
177
178           js_type = js_fifo;
179         }
180     }
181 #endif
182
183   if (js_type == js_none)
184     {
185       if (style && strcmp (style, "pipe") != 0)
186         OS (fatal, NILF, _("Unknown jobserver auth style '%s'"), style);
187
188       EINTRLOOP (r, pipe (job_fds));
189       if (r < 0)
190         pfatal_with_name (_("creating jobs pipe"));
191
192       js_type = js_pipe;
193     }
194
195   /* By default we don't send the job pipe FDs to our children.
196      See jobserver_pre_child() and jobserver_post_child().  */
197   fd_noinherit (job_fds[0]);
198   fd_noinherit (job_fds[1]);
199
200   if (make_job_rfd () < 0)
201     pfatal_with_name (_("duping jobs pipe"));
202
203   while (slots--)
204     {
205       EINTRLOOP (r, write (job_fds[1], &token, 1));
206       if (r != 1)
207         pfatal_with_name (_("init jobserver pipe"));
208     }
209
210   /* When using pselect() we want the read to be non-blocking.  */
211   set_blocking (job_fds[0], 0);
212
213   job_root = 1;
214
215   return 1;
216 }
217
218 unsigned int
219 jobserver_parse_auth (const char *auth)
220 {
221   int rfd, wfd;
222
223   /* Given the command-line parameter, parse it.  */
224
225   /* First see if we're using a named pipe.  */
226   if (strncmp (auth, FIFO_PREFIX, CSTRLEN (FIFO_PREFIX)) == 0)
227     {
228       fifo_name = xstrdup (auth + CSTRLEN (FIFO_PREFIX));
229
230       EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY));
231       if (job_fds[0] < 0)
232         OSS (fatal, NILF,
233              _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno));
234
235       EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
236       if (job_fds[0] < 0)
237         OSS (fatal, NILF,
238              _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno));
239
240       js_type = js_fifo;
241     }
242   /* If not, it must be a simple pipe.  */
243   else if (sscanf (auth, "%d,%d", &rfd, &wfd) == 2)
244     {
245       /* The parent overrode our FDs because we aren't a recursive make.  */
246       if (rfd == -2 || wfd == -2)
247         return 0;
248
249       /* Make sure our pipeline is valid.  */
250       if (!FD_OK (rfd) || !FD_OK (wfd))
251         return 0;
252
253       job_fds[0] = rfd;
254       job_fds[1] = wfd;
255
256       js_type = js_pipe;
257     }
258   /* Who knows what it is?  */
259   else
260     {
261       OS (error, NILF, _("invalid --jobserver-auth string '%s'"), auth);
262       return 0;
263     }
264
265   /* Create a duplicate pipe, if needed, that will be closed in the SIGCHLD
266      handler.  If this fails with EBADF, the parent closed the pipe on us as
267      it didn't think we were a submake.  If so, warn and default to -j1.  */
268
269   if (make_job_rfd () < 0)
270     {
271       if (errno != EBADF)
272         pfatal_with_name ("jobserver readfd");
273
274       jobserver_clear ();
275
276       return 0;
277     }
278
279   /* When using pselect() we want the read to be non-blocking.  */
280   set_blocking (job_fds[0], 0);
281
282   /* By default we don't send the job pipe FDs to our children.
283      See jobserver_pre_child() and jobserver_post_child().  */
284   fd_noinherit (job_fds[0]);
285   fd_noinherit (job_fds[1]);
286
287   return 1;
288 }
289
290 char *
291 jobserver_get_auth ()
292 {
293   char *auth;
294
295   if (js_type == js_fifo) {
296     auth = xmalloc (strlen (fifo_name) + CSTRLEN (FIFO_PREFIX) + 1);
297     sprintf (auth, FIFO_PREFIX "%s", fifo_name);
298   } else {
299     auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
300     sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
301   }
302
303   return auth;
304 }
305
306 const char *
307 jobserver_get_invalid_auth ()
308 {
309   /* If we're using a named pipe we don't need to invalidate the jobserver.  */
310   if (js_type == js_fifo) {
311     return NULL;
312   }
313
314   /* It's not really great that we are assuming the command line option
315      here but other alternatives are also gross.  */
316   return " --" JOBSERVER_AUTH_OPT "=-2,-2";
317 }
318
319 unsigned int
320 jobserver_enabled ()
321 {
322   return js_type != js_none;
323 }
324
325 void
326 jobserver_clear ()
327 {
328   if (job_fds[0] >= 0)
329     close (job_fds[0]);
330   if (job_fds[1] >= 0)
331     close (job_fds[1]);
332   if (job_rfd >= 0)
333     close (job_rfd);
334
335   job_fds[0] = job_fds[1] = job_rfd = -1;
336
337   if (fifo_name)
338     {
339       if (job_root)
340         {
341           int r;
342           EINTRLOOP (r, unlink (fifo_name));
343         }
344
345       if (!handling_fatal_signal)
346         {
347           free (fifo_name);
348           fifo_name = NULL;
349         }
350     }
351
352   js_type = js_none;
353 }
354
355 void
356 jobserver_release (int is_fatal)
357 {
358   int r;
359   EINTRLOOP (r, write (job_fds[1], &token, 1));
360   if (r != 1)
361     {
362       if (is_fatal)
363         pfatal_with_name (_("write jobserver"));
364       perror_with_name ("write", "");
365     }
366 }
367
368 unsigned int
369 jobserver_acquire_all ()
370 {
371   int r;
372   unsigned int tokens = 0;
373
374   /* Use blocking reads to wait for all outstanding jobs.  */
375   set_blocking (job_fds[0], 1);
376
377   /* Close the write side, so the read() won't hang forever.  */
378   close (job_fds[1]);
379   job_fds[1] = -1;
380
381   while (1)
382     {
383       char intake;
384       EINTRLOOP (r, read (job_fds[0], &intake, 1));
385       if (r != 1)
386         break;
387       ++tokens;
388     }
389
390   DB (DB_JOBS, ("Acquired all %u jobserver tokens.\n", tokens));
391
392   jobserver_clear ();
393
394   return tokens;
395 }
396
397 /* Prepare the jobserver to start a child process.  */
398 void
399 jobserver_pre_child (int recursive)
400 {
401   if (recursive && js_type == js_pipe)
402     {
403       fd_inherit (job_fds[0]);
404       fd_inherit (job_fds[1]);
405     }
406 }
407
408 /* Reconfigure the jobserver after starting a child process.  */
409 void
410 jobserver_post_child (int recursive)
411 {
412   if (recursive && js_type == js_pipe)
413     {
414       fd_noinherit (job_fds[0]);
415       fd_noinherit (job_fds[1]);
416     }
417 }
418
419 void
420 jobserver_signal ()
421 {
422   if (job_rfd >= 0)
423     {
424       close (job_rfd);
425       job_rfd = -1;
426     }
427 }
428
429 void
430 jobserver_pre_acquire ()
431 {
432   /* Make sure we have a dup'd FD.  */
433   if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0)
434     pfatal_with_name (_("duping jobs pipe"));
435 }
436
437 #ifdef HAVE_PSELECT
438
439 /* Use pselect() to atomically wait for both a signal and a file descriptor.
440    It also provides a timeout facility so we don't need to use SIGALRM.
441
442    This method relies on the fact that SIGCHLD will be blocked everywhere,
443    and only unblocked (atomically) within the pselect() call, so we can
444    never miss a SIGCHLD.
445  */
446 unsigned int
447 jobserver_acquire (int timeout)
448 {
449   struct timespec spec;
450   struct timespec *specp = NULL;
451   sigset_t empty;
452
453   sigemptyset (&empty);
454
455   if (timeout)
456     {
457       /* Alarm after one second (is this too granular?)  */
458       spec.tv_sec = 1;
459       spec.tv_nsec = 0;
460       specp = &spec;
461     }
462
463   while (1)
464     {
465       fd_set readfds;
466       int r;
467       char intake;
468
469       FD_ZERO (&readfds);
470       FD_SET (job_fds[0], &readfds);
471
472       r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty);
473       if (r < 0)
474         switch (errno)
475           {
476           case EINTR:
477             /* SIGCHLD will show up as an EINTR.  */
478             return 0;
479
480           case EBADF:
481             /* Someone closed the jobs pipe.
482                That shouldn't happen but if it does we're done.  */
483             O (fatal, NILF, _("job server shut down"));
484
485           default:
486             pfatal_with_name (_("pselect jobs pipe"));
487           }
488
489       if (r == 0)
490         /* Timeout.  */
491         return 0;
492
493       /* The read FD is ready: read it!  This is non-blocking.  */
494       EINTRLOOP (r, read (job_fds[0], &intake, 1));
495
496       if (r < 0)
497         {
498           /* Someone sniped our token!  Try again.  */
499           if (errno == EAGAIN)
500             continue;
501
502           pfatal_with_name (_("read jobs pipe"));
503         }
504
505       /* read() should never return 0: only the parent make can reap all the
506          tokens and close the write side...??  */
507       return r > 0;
508     }
509 }
510
511 #else
512
513 /* This method uses a "traditional" UNIX model for waiting on both a signal
514    and a file descriptor.  However, it's complex and since we have a SIGCHLD
515    handler installed we need to check ALL system calls for EINTR: painful!
516
517    Read a token.  As long as there's no token available we'll block.  We
518    enable interruptible system calls before the read(2) so that if we get a
519    SIGCHLD while we're waiting, we'll return with EINTR and we can process the
520    death(s) and return tokens to the free pool.
521
522    Once we return from the read, we immediately reinstate restartable system
523    calls.  This allows us to not worry about checking for EINTR on all the
524    other system calls in the program.
525
526    There is one other twist: there is a span between the time reap_children()
527    does its last check for dead children and the time the read(2) call is
528    entered, below, where if a child dies we won't notice.  This is extremely
529    serious as it could cause us to deadlock, given the right set of events.
530
531    To avoid this, we do the following: before we reap_children(), we dup(2)
532    the read FD on the jobserver pipe.  The read(2) call below uses that new
533    FD.  In the signal handler, we close that FD.  That way, if a child dies
534    during the section mentioned above, the read(2) will be invoked with an
535    invalid FD and will return immediately with EBADF.  */
536
537 static void
538 job_noop (int sig UNUSED)
539 {
540 }
541
542 /* Set the child handler action flags to FLAGS.  */
543 static void
544 set_child_handler_action_flags (int set_handler, int set_alarm)
545 {
546   struct sigaction sa;
547
548 #ifdef __EMX__
549   /* The child handler must be turned off here.  */
550   signal (SIGCHLD, SIG_DFL);
551 #endif
552
553   memset (&sa, '\0', sizeof sa);
554   sa.sa_handler = child_handler;
555   sa.sa_flags = set_handler ? 0 : SA_RESTART;
556
557 #if defined SIGCHLD
558   if (sigaction (SIGCHLD, &sa, NULL) < 0)
559     pfatal_with_name ("sigaction: SIGCHLD");
560 #endif
561
562 #if defined SIGCLD && SIGCLD != SIGCHLD
563   if (sigaction (SIGCLD, &sa, NULL) < 0)
564     pfatal_with_name ("sigaction: SIGCLD");
565 #endif
566
567 #if defined SIGALRM
568   if (set_alarm)
569     {
570       /* If we're about to enter the read(), set an alarm to wake up in a
571          second so we can check if the load has dropped and we can start more
572          work.  On the way out, turn off the alarm and set SIG_DFL.  */
573       if (set_handler)
574         {
575           sa.sa_handler = job_noop;
576           sa.sa_flags = 0;
577           if (sigaction (SIGALRM, &sa, NULL) < 0)
578             pfatal_with_name ("sigaction: SIGALRM");
579           alarm (1);
580         }
581       else
582         {
583           alarm (0);
584           sa.sa_handler = SIG_DFL;
585           sa.sa_flags = 0;
586           if (sigaction (SIGALRM, &sa, NULL) < 0)
587             pfatal_with_name ("sigaction: SIGALRM");
588         }
589     }
590 #endif
591 }
592
593 unsigned int
594 jobserver_acquire (int timeout)
595 {
596   char intake;
597   int got_token;
598   int saved_errno;
599
600   /* Set interruptible system calls, and read() for a job token.  */
601   set_child_handler_action_flags (1, timeout);
602
603   EINTRLOOP (got_token, read (job_rfd, &intake, 1));
604   saved_errno = errno;
605
606   set_child_handler_action_flags (0, timeout);
607
608   if (got_token == 1)
609     return 1;
610
611   /* If the error _wasn't_ expected (EINTR or EBADF), fatal.  Otherwise,
612      go back and reap_children(), and try again.  */
613   errno = saved_errno;
614
615   if (errno != EINTR && errno != EBADF)
616     pfatal_with_name (_("read jobs pipe"));
617
618   if (errno == EBADF)
619     DB (DB_JOBS, ("Read returned EBADF.\n"));
620
621   return 0;
622 }
623
624 #endif /* HAVE_PSELECT */
625
626 #endif /* MAKE_JOBSERVER */
627
628 #if !defined(NO_OUTPUT_SYNC)
629
630 #define MUTEX_PREFIX    "fnm:"
631
632 static int osync_handle = -1;
633
634 static char *osync_tmpfile = NULL;
635
636 static unsigned int sync_root = 0;
637
638 unsigned int
639 osync_enabled ()
640 {
641   return osync_handle >= 0;
642 }
643
644 void
645 osync_setup ()
646 {
647   osync_handle = get_tmpfd (&osync_tmpfile);
648   fd_noinherit (osync_handle);
649   sync_root = 1;
650 }
651
652 char *
653 osync_get_mutex ()
654 {
655   char *mutex = NULL;
656
657   if (osync_enabled ())
658     {
659       /* Prepare the mutex handle string for our children.  */
660       mutex = xmalloc (strlen (osync_tmpfile) + CSTRLEN (MUTEX_PREFIX) + 1);
661       sprintf (mutex, MUTEX_PREFIX "%s", osync_tmpfile);
662     }
663
664   return mutex;
665 }
666
667 unsigned int
668 osync_parse_mutex (const char *mutex)
669 {
670   if (strncmp (mutex, MUTEX_PREFIX, CSTRLEN (MUTEX_PREFIX)) != 0)
671     {
672       OS (error, NILF, _("invalid --sync-mutex string '%s'"), mutex);
673       return 0;
674     }
675
676   free (osync_tmpfile);
677   osync_tmpfile = xstrdup (mutex + CSTRLEN (MUTEX_PREFIX));
678
679   EINTRLOOP (osync_handle, open (osync_tmpfile, O_WRONLY));
680   if (osync_handle < 0)
681     OSS (fatal, NILF, _("cannot open output sync mutex %s: %s"),
682          osync_tmpfile, strerror (errno));
683
684   fd_noinherit (osync_handle);
685
686   return 1;
687 }
688
689 void
690 osync_clear ()
691 {
692   if (osync_handle >= 0)
693     {
694       close (osync_handle);
695       osync_handle = -1;
696     }
697
698   if (sync_root && osync_tmpfile)
699     {
700       int r;
701
702       EINTRLOOP (r, unlink (osync_tmpfile));
703       free (osync_tmpfile);
704       osync_tmpfile = NULL;
705     }
706 }
707
708 unsigned int
709 osync_acquire ()
710 {
711   if (osync_enabled())
712     {
713       struct flock fl;
714
715       fl.l_type = F_WRLCK;
716       fl.l_whence = SEEK_SET;
717       fl.l_start = 0;
718       fl.l_len = 1;
719       /* We don't want to keep waiting on EINTR.  */
720       if (fcntl (osync_handle, F_SETLKW, &fl) == -1)
721         {
722           perror ("fcntl()");
723           return 0;
724         }
725     }
726
727   return 1;
728 }
729
730 void
731 osync_release ()
732 {
733   if (osync_enabled())
734     {
735       struct flock fl;
736
737       fl.l_type = F_UNLCK;
738       fl.l_whence = SEEK_SET;
739       fl.l_start = 0;
740       fl.l_len = 1;
741       /* We don't want to keep waiting on EINTR.  */
742       if (fcntl (osync_handle, F_SETLKW, &fl) == -1)
743         perror ("fcntl()");
744     }
745 }
746
747 #endif
748
749 /* Create a "bad" file descriptor for stdin when parallel jobs are run.  */
750 int
751 get_bad_stdin ()
752 {
753   static int bad_stdin = -1;
754
755   /* Set up a bad standard input that reads from a broken pipe.  */
756
757   if (bad_stdin == -1)
758     {
759       /* Make a file descriptor that is the read end of a broken pipe.
760          This will be used for some children's standard inputs.  */
761       int pd[2];
762       if (pipe (pd) == 0)
763         {
764           /* Close the write side.  */
765           close (pd[1]);
766           /* Save the read side.  */
767           bad_stdin = pd[0];
768
769           /* Set the descriptor to close on exec, so it does not litter any
770              child's descriptor table.  When it is dup2'd onto descriptor 0,
771              that descriptor will not close on exec.  */
772           fd_noinherit (bad_stdin);
773         }
774     }
775
776   return bad_stdin;
777 }
778
779 /* Set file descriptors to be inherited / not inherited by subprocesses.  */
780
781 #if !defined(F_SETFD) || !defined(F_GETFD)
782 void fd_inherit (int fd) {}
783 void fd_noinherit (int fd) {}
784
785 #else
786
787 # ifndef FD_CLOEXEC
788 #  define FD_CLOEXEC 1
789 # endif
790
791 void
792 fd_inherit (int fd)
793 {
794   int flags;
795   EINTRLOOP (flags, fcntl (fd, F_GETFD));
796   if (flags >= 0)
797     {
798       int r;
799       flags &= ~FD_CLOEXEC;
800       EINTRLOOP (r, fcntl (fd, F_SETFD, flags));
801     }
802 }
803
804 void
805 fd_noinherit (int fd)
806 {
807     int flags;
808     EINTRLOOP (flags, fcntl(fd, F_GETFD));
809     if (flags >= 0)
810       {
811         int r;
812         flags |= FD_CLOEXEC;
813         EINTRLOOP (r, fcntl(fd, F_SETFD, flags));
814       }
815 }
816 #endif
817
818 /* Set a file descriptor referring to a regular file to be in O_APPEND mode.
819    If it fails, just ignore it.  */
820
821 void
822 fd_set_append (int fd)
823 {
824 #if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
825   struct stat stbuf;
826   int flags;
827   if (fstat (fd, &stbuf) == 0 && S_ISREG (stbuf.st_mode))
828     {
829       flags = fcntl (fd, F_GETFL, 0);
830       if (flags >= 0)
831         {
832           int r;
833           EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND));
834         }
835     }
836 #endif
837 }
838
839 /* Return a file descriptor for a new anonymous temp file, or -1.  */
840 int
841 os_anontmp ()
842 {
843   const char *tdir = get_tmpdir ();
844   int fd = -1;
845
846 #ifdef O_TMPFILE
847   static unsigned int tmpfile_works = 1;
848
849   if (tmpfile_works)
850     {
851       EINTRLOOP (fd, open (tdir, O_RDWR | O_TMPFILE | O_EXCL, 0600));
852       if (fd >= 0)
853         return fd;
854
855       DB (DB_BASIC, (_("Cannot open '%s' with O_TMPFILE: %s.\n"),
856                      tdir, strerror (errno)));
857       tmpfile_works = 0;
858     }
859 #endif
860
861 #if HAVE_DUP
862   /* If we can dup and we are creating temp files in the default location then
863      try tmpfile() + dup() + fclose() to avoid ever having a named file.  */
864   if (streq (tdir, DEFAULT_TMPDIR))
865     {
866       mode_t mask = umask (0077);
867       FILE *tfile;
868       ENULLLOOP (tfile, tmpfile ());
869       if (!tfile)
870         pfatal_with_name ("tmpfile");
871       umask (mask);
872
873       EINTRLOOP (fd, dup (fileno (tfile)));
874       if (fd < 0)
875         pfatal_with_name ("dup");
876       fclose (tfile);
877     }
878 #endif
879
880   return fd;
881 }