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 }