]>
Commit | Line | Data |
---|---|---|
a600e5ce | 1 | /* Catastrophic failure reports. Generic POSIX.1 version. |
581c785b | 2 | Copyright (C) 1993-2022 Free Software Foundation, Inc. |
ebbad4cc | 3 | This file is part of the GNU C Library. |
28f540f4 | 4 | |
ebbad4cc | 5 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
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. | |
28f540f4 | 9 | |
ebbad4cc UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
28f540f4 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
28f540f4 | 18 | |
48dcd0ba | 19 | #include <atomic.h> |
1327439f UD |
20 | #include <errno.h> |
21 | #include <fcntl.h> | |
f8a3b5bf | 22 | #include <ldsodefs.h> |
1327439f UD |
23 | #include <paths.h> |
24 | #include <stdarg.h> | |
25 | #include <stdbool.h> | |
28f540f4 | 26 | #include <stdio.h> |
ef52edfc | 27 | #include <stdlib.h> |
7f811679 | 28 | #include <string.h> |
1327439f UD |
29 | #include <sysdep.h> |
30 | #include <unistd.h> | |
a600e5ce | 31 | #include <sys/mman.h> |
579e2d6e | 32 | #include <sys/uio.h> |
1327439f | 33 | #include <not-cancel.h> |
28f540f4 RM |
34 | |
35 | #ifdef FATAL_PREPARE_INCLUDE | |
36 | #include FATAL_PREPARE_INCLUDE | |
37 | #endif | |
38 | ||
a600e5ce RM |
39 | #ifndef WRITEV_FOR_FATAL |
40 | # define WRITEV_FOR_FATAL writev_for_fatal | |
41 | static bool | |
42 | writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total) | |
43 | { | |
44 | return TEMP_FAILURE_RETRY (__writev (fd, iov, niov)) == total; | |
45 | } | |
46 | #endif | |
47 | ||
1327439f UD |
48 | struct str_list |
49 | { | |
50 | const char *str; | |
51 | size_t len; | |
52 | struct str_list *next; | |
53 | }; | |
54 | ||
28f540f4 RM |
55 | /* Abort with an error message. */ |
56 | void | |
ed421fca | 57 | __libc_message (enum __libc_message_action action, const char *fmt, ...) |
28f540f4 | 58 | { |
1327439f | 59 | va_list ap; |
1327439f UD |
60 | int fd = -1; |
61 | ||
62 | va_start (ap, fmt); | |
28f540f4 RM |
63 | |
64 | #ifdef FATAL_PREPARE | |
65 | FATAL_PREPARE; | |
66 | #endif | |
67 | ||
1327439f UD |
68 | if (fd == -1) |
69 | fd = STDERR_FILENO; | |
70 | ||
71 | struct str_list *list = NULL; | |
72 | int nlist = 0; | |
73 | ||
74 | const char *cp = fmt; | |
75 | while (*cp != '\0') | |
28f540f4 | 76 | { |
1327439f | 77 | /* Find the next "%s" or the end of the string. */ |
8ad684db | 78 | const char *next = cp; |
1327439f | 79 | while (next[0] != '%' || next[1] != 's') |
28f540f4 | 80 | { |
1327439f UD |
81 | next = __strchrnul (next + 1, '%'); |
82 | ||
83 | if (next[0] == '\0') | |
84 | break; | |
28f540f4 | 85 | } |
1327439f UD |
86 | |
87 | /* Determine what to print. */ | |
88 | const char *str; | |
89 | size_t len; | |
90 | if (cp[0] == '%' && cp[1] == 's') | |
91 | { | |
92 | str = va_arg (ap, const char *); | |
93 | len = strlen (str); | |
94 | cp += 2; | |
95 | } | |
96 | else | |
97 | { | |
98 | str = cp; | |
99 | len = next - cp; | |
100 | cp = next; | |
101 | } | |
102 | ||
103 | struct str_list *newp = alloca (sizeof (struct str_list)); | |
104 | newp->str = str; | |
105 | newp->len = len; | |
106 | newp->next = list; | |
107 | list = newp; | |
108 | ++nlist; | |
109 | } | |
110 | ||
1327439f UD |
111 | if (nlist > 0) |
112 | { | |
113 | struct iovec *iov = alloca (nlist * sizeof (struct iovec)); | |
114 | ssize_t total = 0; | |
115 | ||
116 | for (int cnt = nlist - 1; cnt >= 0; --cnt) | |
117 | { | |
8ad684db | 118 | iov[cnt].iov_base = (char *) list->str; |
1327439f UD |
119 | iov[cnt].iov_len = list->len; |
120 | total += list->len; | |
121 | list = list->next; | |
122 | } | |
123 | ||
a289ea09 | 124 | WRITEV_FOR_FATAL (fd, iov, nlist, total); |
48dcd0ba | 125 | |
ed421fca | 126 | if ((action & do_abort)) |
48dcd0ba | 127 | { |
f8a3b5bf UD |
128 | total = ((total + 1 + GLRO(dl_pagesize) - 1) |
129 | & ~(GLRO(dl_pagesize) - 1)); | |
130 | struct abort_msg_s *buf = __mmap (NULL, total, | |
131 | PROT_READ | PROT_WRITE, | |
132 | MAP_ANON | MAP_PRIVATE, -1, 0); | |
a600e5ce | 133 | if (__glibc_likely (buf != MAP_FAILED)) |
f8a3b5bf UD |
134 | { |
135 | buf->size = total; | |
136 | char *wp = buf->msg; | |
137 | for (int cnt = 0; cnt < nlist; ++cnt) | |
138 | wp = mempcpy (wp, iov[cnt].iov_base, iov[cnt].iov_len); | |
139 | *wp = '\0'; | |
140 | ||
141 | /* We have to free the old buffer since the application might | |
142 | catch the SIGABRT signal. */ | |
143 | struct abort_msg_s *old = atomic_exchange_acq (&__abort_msg, | |
144 | buf); | |
145 | if (old != NULL) | |
146 | __munmap (old, old->size); | |
147 | } | |
48dcd0ba | 148 | } |
28f540f4 RM |
149 | } |
150 | ||
1327439f UD |
151 | va_end (ap); |
152 | ||
ed421fca | 153 | if ((action & do_abort)) |
a289ea09 FW |
154 | /* Kill the application. */ |
155 | abort (); | |
1327439f UD |
156 | } |
157 | ||
158 | ||
159 | void | |
bd2260a2 | 160 | __libc_fatal (const char *message) |
1327439f | 161 | { |
f895670d UD |
162 | /* The loop is added only to keep gcc happy. */ |
163 | while (1) | |
a289ea09 | 164 | __libc_message (do_abort, "%s", message); |
28f540f4 | 165 | } |
9d79e037 | 166 | libc_hidden_def (__libc_fatal) |