Commit | Line | Data |
---|---|---|
a6bc4ca9 SM |
1 | /* |
2 | * Copyright (C) 2012 David Goulet <dgoulet@efficios.com> | |
3 | * | |
c922647d | 4 | * SPDX-License-Identifier: LGPL-2.1-only |
a6bc4ca9 SM |
5 | * |
6 | */ | |
7 | ||
8 | #define _LGPL_SOURCE | |
9 | #include <inttypes.h> | |
10 | #include <pthread.h> | |
11 | #include <stdlib.h> | |
12 | #include <string.h> | |
13 | ||
c9e313bc SM |
14 | #include <common/common.hpp> |
15 | #include <common/thread.hpp> | |
16 | #include <common/compat/errno.hpp> | |
17 | #include <common/compat/getenv.hpp> | |
a6bc4ca9 SM |
18 | #include <lttng/lttng-error.h> |
19 | ||
c9e313bc | 20 | #include "error.hpp" |
a6bc4ca9 SM |
21 | |
22 | /* | |
23 | * lttng_opt_abort_on_error: unset: -1, disabled: 0, enabled: 1. | |
24 | * Controlled by the LTTNG_ABORT_ON_ERROR environment variable. | |
25 | */ | |
26 | static int lttng_opt_abort_on_error = -1; | |
27 | ||
28 | /* TLS variable that contains the time of one single log entry. */ | |
29 | DEFINE_URCU_TLS(struct log_time, error_log_time); | |
30 | DEFINE_URCU_TLS(const char *, logger_thread_name); | |
31 | ||
32 | const char *log_add_time(void) | |
33 | { | |
34 | int ret; | |
35 | struct tm tm, *res; | |
36 | struct timespec tp; | |
37 | time_t now; | |
38 | const int errsv = errno; | |
39 | ||
40 | ret = lttng_clock_gettime(CLOCK_REALTIME, &tp); | |
41 | if (ret < 0) { | |
42 | goto error; | |
43 | } | |
44 | now = (time_t) tp.tv_sec; | |
45 | ||
46 | res = localtime_r(&now, &tm); | |
47 | if (!res) { | |
48 | goto error; | |
49 | } | |
50 | ||
51 | /* Format time in the TLS variable. */ | |
52 | ret = snprintf(URCU_TLS(error_log_time).str, sizeof(URCU_TLS(error_log_time).str), | |
53 | "%02d:%02d:%02d.%09ld", | |
54 | tm.tm_hour, tm.tm_min, tm.tm_sec, tp.tv_nsec); | |
55 | if (ret < 0) { | |
56 | goto error; | |
57 | } | |
58 | ||
59 | errno = errsv; | |
60 | return URCU_TLS(error_log_time).str; | |
61 | ||
62 | error: | |
63 | /* Return an empty string on error so logging is not affected. */ | |
64 | errno = errsv; | |
65 | return ""; | |
66 | } | |
67 | ||
68 | void logger_set_thread_name(const char *name, bool set_pthread_name) | |
69 | { | |
70 | int ret; | |
71 | ||
72 | LTTNG_ASSERT(name); | |
73 | URCU_TLS(logger_thread_name) = name; | |
74 | ||
75 | if (set_pthread_name) { | |
76 | ret = lttng_thread_setname(name); | |
77 | if (ret && ret != -ENOSYS) { | |
78 | /* Don't fail as this is not essential. */ | |
79 | DBG("Failed to set pthread name attribute"); | |
80 | } | |
81 | } | |
82 | } | |
83 | ||
84 | /* | |
85 | * Human readable error message. | |
86 | */ | |
87 | static | |
88 | const char *lttng_error_code_str(lttng_error_code code) | |
89 | { | |
90 | switch (code) { | |
91 | case LTTNG_OK: | |
92 | return "Success"; | |
93 | case LTTNG_ERR_UNK: | |
94 | return "Unknown error"; | |
95 | case LTTNG_ERR_UND: | |
96 | return "Undefined command"; | |
97 | case LTTNG_ERR_UNKNOWN_DOMAIN: | |
98 | return "Unknown tracing domain"; | |
99 | case LTTNG_ERR_NO_SESSION: | |
100 | return "No session found"; | |
101 | case LTTNG_ERR_CREATE_DIR_FAIL: | |
102 | return "Create directory failed"; | |
103 | case LTTNG_ERR_SESSION_FAIL: | |
104 | return "Create session failed"; | |
105 | case LTTNG_ERR_SESS_NOT_FOUND: | |
106 | return "Session name not found"; | |
107 | case LTTNG_ERR_FATAL: | |
108 | return "Fatal error of the session daemon"; | |
109 | case LTTNG_ERR_SELECT_SESS: | |
110 | return "A session MUST be selected"; | |
111 | case LTTNG_ERR_EXIST_SESS: | |
112 | return "Session name already exists"; | |
113 | case LTTNG_ERR_NO_EVENT: | |
114 | return "Event not found"; | |
115 | case LTTNG_ERR_CONNECT_FAIL: | |
116 | return "Unable to connect to Unix socket"; | |
117 | case LTTNG_ERR_EPERM: | |
118 | return "Permission denied"; | |
119 | case LTTNG_ERR_KERN_NA: | |
120 | return "Kernel tracer not available"; | |
121 | case LTTNG_ERR_KERN_VERSION: | |
122 | return "Kernel tracer version is not compatible"; | |
123 | case LTTNG_ERR_KERN_EVENT_EXIST: | |
124 | return "Kernel event already exists"; | |
125 | case LTTNG_ERR_KERN_SESS_FAIL: | |
126 | return "Kernel create session failed"; | |
127 | case LTTNG_ERR_KERN_CHAN_EXIST: | |
128 | return "Kernel channel already exists"; | |
129 | case LTTNG_ERR_KERN_CHAN_FAIL: | |
130 | return "Kernel create channel failed"; | |
131 | case LTTNG_ERR_KERN_CHAN_NOT_FOUND: | |
132 | return "Kernel channel not found"; | |
133 | case LTTNG_ERR_KERN_CHAN_DISABLE_FAIL: | |
134 | return "Disable kernel channel failed"; | |
135 | case LTTNG_ERR_KERN_CHAN_ENABLE_FAIL: | |
136 | return "Enable kernel channel failed"; | |
137 | case LTTNG_ERR_KERN_CONTEXT_FAIL: | |
138 | return "Add kernel context failed"; | |
139 | case LTTNG_ERR_KERN_ENABLE_FAIL: | |
140 | return "Enable kernel event failed"; | |
141 | case LTTNG_ERR_KERN_DISABLE_FAIL: | |
142 | return "Disable kernel event failed"; | |
143 | case LTTNG_ERR_KERN_META_FAIL: | |
144 | return "Opening metadata failed"; | |
145 | case LTTNG_ERR_KERN_START_FAIL: | |
146 | return "Starting kernel trace failed"; | |
147 | case LTTNG_ERR_KERN_STOP_FAIL: | |
148 | return "Stopping kernel trace failed"; | |
149 | case LTTNG_ERR_KERN_CONSUMER_FAIL: | |
150 | return "Kernel consumer start failed"; | |
151 | case LTTNG_ERR_KERN_STREAM_FAIL: | |
152 | return "Kernel create stream failed"; | |
153 | case LTTNG_ERR_KERN_LIST_FAIL: | |
154 | return "Listing kernel events failed"; | |
155 | case LTTNG_ERR_UST_CALIBRATE_FAIL: | |
156 | return "UST calibration failed"; | |
157 | case LTTNG_ERR_UST_SESS_FAIL: | |
158 | return "UST create session failed"; | |
159 | case LTTNG_ERR_UST_CHAN_FAIL: | |
160 | return "UST create channel failed"; | |
161 | case LTTNG_ERR_UST_CHAN_EXIST: | |
162 | return "UST channel already exist"; | |
163 | case LTTNG_ERR_UST_CHAN_NOT_FOUND: | |
164 | return "UST channel not found"; | |
165 | case LTTNG_ERR_UST_CHAN_DISABLE_FAIL: | |
166 | return "Disable UST channel failed"; | |
167 | case LTTNG_ERR_UST_CHAN_ENABLE_FAIL: | |
168 | return "Enable UST channel failed"; | |
169 | case LTTNG_ERR_UST_ENABLE_FAIL: | |
170 | return "Enable UST event failed"; | |
171 | case LTTNG_ERR_UST_DISABLE_FAIL: | |
172 | return "Disable UST event failed"; | |
173 | case LTTNG_ERR_UST_META_FAIL: | |
174 | return "Opening metadata failed"; | |
175 | case LTTNG_ERR_UST_START_FAIL: | |
176 | return "Starting UST trace failed"; | |
177 | case LTTNG_ERR_UST_STOP_FAIL: | |
178 | return "Stopping UST trace failed"; | |
179 | case LTTNG_ERR_UST_CONSUMER64_FAIL: | |
180 | return "64-bit UST consumer start failed"; | |
181 | case LTTNG_ERR_UST_CONSUMER32_FAIL: | |
182 | return "32-bit UST consumer start failed"; | |
183 | case LTTNG_ERR_UST_STREAM_FAIL: | |
184 | return "UST create stream failed"; | |
185 | case LTTNG_ERR_UST_LIST_FAIL: | |
186 | return "Listing UST events failed"; | |
187 | case LTTNG_ERR_UST_EVENT_EXIST: | |
188 | return "UST event already exist"; | |
189 | case LTTNG_ERR_UST_EVENT_NOT_FOUND: | |
190 | return "UST event not found"; | |
191 | case LTTNG_ERR_UST_CONTEXT_EXIST: | |
192 | return "UST context already exist"; | |
193 | case LTTNG_ERR_UST_CONTEXT_INVAL: | |
194 | return "UST invalid context"; | |
195 | case LTTNG_ERR_NEED_ROOT_SESSIOND: | |
196 | return "Tracing the kernel requires a root lttng-sessiond daemon, as well as \"tracing\" group membership or root user ID for the lttng client"; | |
197 | case LTTNG_ERR_NO_UST: | |
198 | return "LTTng-UST tracer is not supported. Please rebuild lttng-tools with lttng-ust support enabled"; | |
199 | case LTTNG_ERR_TRACE_ALREADY_STARTED: | |
200 | return "Tracing has already been started once"; | |
201 | case LTTNG_ERR_TRACE_ALREADY_STOPPED: | |
202 | return "Tracing has already been stopped"; | |
203 | case LTTNG_ERR_KERN_EVENT_ENOSYS: | |
204 | return "Kernel event type not supported"; | |
205 | case LTTNG_ERR_NEED_CHANNEL_NAME: | |
206 | return "Non-default channel exists within session: channel name needs to be specified with '-c name'"; | |
207 | case LTTNG_ERR_INVALID: | |
208 | return "Invalid parameter"; | |
209 | case LTTNG_ERR_NO_USTCONSUMERD: | |
210 | return "No UST consumer detected"; | |
211 | case LTTNG_ERR_NO_KERNCONSUMERD: | |
212 | return "No kernel consumer detected"; | |
213 | case LTTNG_ERR_EVENT_EXIST_LOGLEVEL: | |
214 | return "Event already enabled with different loglevel"; | |
215 | case LTTNG_ERR_URL_DATA_MISS: | |
216 | return "Missing data path URL"; | |
217 | case LTTNG_ERR_URL_CTRL_MISS: | |
218 | return "Missing control path URL"; | |
219 | case LTTNG_ERR_ENABLE_CONSUMER_FAIL: | |
220 | return "Enabling consumer failed"; | |
221 | case LTTNG_ERR_RELAYD_CONNECT_FAIL: | |
222 | return "Unable to connect to lttng-relayd"; | |
223 | case LTTNG_ERR_RELAYD_VERSION_FAIL: | |
224 | return "Relay daemon not compatible"; | |
225 | case LTTNG_ERR_FILTER_INVAL: | |
226 | return "Invalid filter bytecode"; | |
227 | case LTTNG_ERR_FILTER_NOMEM: | |
228 | return "Not enough memory for filter bytecode"; | |
229 | case LTTNG_ERR_FILTER_EXIST: | |
230 | return "Filter already exist"; | |
231 | case LTTNG_ERR_NO_CONSUMER: | |
232 | return "Consumer not found for recording session"; | |
233 | case LTTNG_ERR_EXCLUSION_INVAL: | |
234 | return "Invalid event exclusion data"; | |
235 | case LTTNG_ERR_EXCLUSION_NOMEM: | |
236 | return "Lack of memory while processing event exclusions"; | |
237 | case LTTNG_ERR_NO_SESSIOND: | |
238 | return "No session daemon is available"; | |
239 | case LTTNG_ERR_SESSION_STARTED: | |
240 | return "Session is running"; | |
241 | case LTTNG_ERR_NOT_SUPPORTED: | |
242 | return "Operation not supported"; | |
243 | case LTTNG_ERR_UST_EVENT_ENABLED: | |
244 | return "UST event already enabled"; | |
245 | case LTTNG_ERR_SET_URL: | |
246 | return "Error setting URL"; | |
247 | case LTTNG_ERR_URL_EXIST: | |
248 | return "URL already exists"; | |
249 | case LTTNG_ERR_BUFFER_NOT_SUPPORTED: | |
250 | return "Buffer type not supported"; | |
251 | case LTTNG_ERR_BUFFER_TYPE_MISMATCH: | |
252 | return "Buffer type mismatch for session"; | |
253 | case LTTNG_ERR_NOMEM: | |
254 | return "Not enough memory"; | |
255 | case LTTNG_ERR_SNAPSHOT_OUTPUT_EXIST: | |
256 | return "Snapshot output already exists"; | |
257 | case LTTNG_ERR_START_SESSION_ONCE: | |
258 | return "Session needs to be started once"; | |
259 | case LTTNG_ERR_SNAPSHOT_FAIL: | |
260 | return "Snapshot record failed"; | |
261 | case LTTNG_ERR_NO_STREAM: | |
262 | return "Index without stream on relay"; | |
263 | case LTTNG_ERR_CHAN_EXIST: | |
264 | return "Channel already exists"; | |
265 | case LTTNG_ERR_SNAPSHOT_NODATA: | |
266 | return "No data available in snapshot"; | |
267 | case LTTNG_ERR_NO_CHANNEL: | |
268 | return "No channel found in the session"; | |
269 | case LTTNG_ERR_SESSION_INVALID_CHAR: | |
270 | return "Invalid character found in session name"; | |
271 | case LTTNG_ERR_SAVE_FILE_EXIST: | |
272 | return "Session file already exists"; | |
273 | case LTTNG_ERR_SAVE_IO_FAIL: | |
274 | return "IO error while writing session configuration"; | |
275 | case LTTNG_ERR_LOAD_INVALID_CONFIG: | |
276 | return "Invalid session configuration"; | |
277 | case LTTNG_ERR_LOAD_IO_FAIL: | |
278 | return "IO error while reading a session configuration"; | |
279 | case LTTNG_ERR_LOAD_SESSION_NOENT: | |
280 | return "Session file not found"; | |
281 | case LTTNG_ERR_MAX_SIZE_INVALID: | |
282 | return "Snapshot max size is invalid"; | |
283 | case LTTNG_ERR_MI_OUTPUT_TYPE: | |
284 | return "Invalid MI output format"; | |
285 | case LTTNG_ERR_MI_IO_FAIL: | |
286 | return "IO error while writing MI output"; | |
287 | case LTTNG_ERR_MI_NOT_IMPLEMENTED: | |
288 | return "Mi feature not implemented"; | |
289 | case LTTNG_ERR_INVALID_EVENT_NAME: | |
290 | return "Invalid event name"; | |
291 | case LTTNG_ERR_INVALID_CHANNEL_NAME: | |
292 | return "Invalid channel name"; | |
293 | case LTTNG_ERR_PROCESS_ATTR_EXISTS: | |
294 | return "Process attribute is already tracked"; | |
295 | case LTTNG_ERR_PROCESS_ATTR_MISSING: | |
296 | return "Process attribute was not tracked"; | |
297 | case LTTNG_ERR_INVALID_CHANNEL_DOMAIN: | |
298 | return "Invalid channel domain"; | |
299 | case LTTNG_ERR_OVERFLOW: | |
300 | return "Overflow occurred"; | |
301 | case LTTNG_ERR_SESSION_NOT_STARTED: | |
302 | return "Session not started"; | |
303 | case LTTNG_ERR_LIVE_SESSION: | |
304 | return "Live sessions are not supported"; | |
305 | case LTTNG_ERR_PER_PID_SESSION: | |
306 | return "Per-PID recording sessions are not supported"; | |
307 | case LTTNG_ERR_KERN_CONTEXT_UNAVAILABLE: | |
308 | return "Context unavailable on this kernel"; | |
309 | case LTTNG_ERR_REGEN_STATEDUMP_FAIL: | |
310 | return "Failed to regenerate the state dump"; | |
311 | case LTTNG_ERR_REGEN_STATEDUMP_NOMEM: | |
312 | return "Failed to regenerate the state dump, not enough memory"; | |
313 | case LTTNG_ERR_NOT_SNAPSHOT_SESSION: | |
314 | return "Snapshot command can't be applied to a non-snapshot session"; | |
315 | case LTTNG_ERR_INVALID_TRIGGER: | |
316 | return "Invalid trigger"; | |
317 | case LTTNG_ERR_TRIGGER_EXISTS: | |
318 | return "Trigger already registered"; | |
319 | case LTTNG_ERR_TRIGGER_NOT_FOUND: | |
320 | return "Trigger not found"; | |
321 | case LTTNG_ERR_COMMAND_CANCELLED: | |
322 | return "Command cancelled"; | |
323 | case LTTNG_ERR_ROTATION_PENDING: | |
324 | return "Rotation already pending for this session"; | |
325 | case LTTNG_ERR_ROTATION_NOT_AVAILABLE: | |
326 | return "Rotation feature not available for this session's creation mode"; | |
327 | case LTTNG_ERR_ROTATION_SCHEDULE_SET: | |
328 | return "A session rotation schedule of this type is already set on the session"; | |
329 | case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET: | |
330 | return "No session rotation schedule of this type is set on the session"; | |
331 | case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP: | |
332 | return "Session was already rotated once since it became inactive"; | |
333 | case LTTNG_ERR_ROTATION_WRONG_VERSION: | |
334 | return "Session rotation is not supported by this kernel tracer version"; | |
335 | case LTTNG_ERR_NO_SESSION_OUTPUT: | |
336 | return "Session has no output"; | |
337 | case LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY: | |
338 | return "Rotation feature not available on the relay"; | |
339 | case LTTNG_ERR_AGENT_TRACING_DISABLED: | |
340 | return "Session daemon agent tracing is disabled"; | |
341 | case LTTNG_ERR_PROBE_LOCATION_INVAL: | |
342 | return "Invalid userspace probe location"; | |
343 | case LTTNG_ERR_ELF_PARSING: | |
344 | return "ELF parsing error"; | |
345 | case LTTNG_ERR_SDT_PROBE_SEMAPHORE: | |
346 | return "SDT probe guarded by a semaphore"; | |
347 | case LTTNG_ERR_ROTATION_FAIL_CONSUMER: | |
348 | return "Rotation failure on consumer"; | |
349 | case LTTNG_ERR_ROTATE_RENAME_FAIL_CONSUMER: | |
350 | return "Rotation rename failure on consumer"; | |
351 | case LTTNG_ERR_ROTATION_PENDING_LOCAL_FAIL_CONSUMER: | |
352 | return "Rotation pending check (local) failure on consumer"; | |
353 | case LTTNG_ERR_ROTATION_PENDING_RELAY_FAIL_CONSUMER: | |
354 | return "Rotation pending check (relay) failure on consumer"; | |
355 | case LTTNG_ERR_MKDIR_FAIL_CONSUMER: | |
356 | return "Directory creation failure on consumer"; | |
357 | case LTTNG_ERR_CHAN_NOT_FOUND: | |
358 | return "Channel not found"; | |
359 | case LTTNG_ERR_SNAPSHOT_UNSUPPORTED: | |
360 | return "Session configuration does not allow the use of snapshots"; | |
361 | case LTTNG_ERR_SESSION_NOT_EXIST: | |
362 | return "Recording session does not exist"; | |
363 | case LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER: | |
364 | return "Trace chunk creation failed on consumer"; | |
365 | case LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER: | |
366 | return "Trace chunk close failed on consumer"; | |
367 | case LTTNG_ERR_TRACE_CHUNK_EXISTS_FAIL_CONSUMER: | |
368 | return "Failed to query consumer for trace chunk existence"; | |
369 | case LTTNG_ERR_INVALID_PROTOCOL: | |
370 | return "Protocol error occurred"; | |
371 | case LTTNG_ERR_FILE_CREATION_ERROR: | |
372 | return "Failed to create file"; | |
373 | case LTTNG_ERR_TIMER_STOP_ERROR: | |
374 | return "Failed to stop a timer"; | |
375 | case LTTNG_ERR_ROTATION_NOT_AVAILABLE_KERNEL: | |
376 | return "Rotation feature not supported by the kernel tracer"; | |
377 | case LTTNG_ERR_CLEAR_RELAY_DISALLOWED: | |
378 | return "Relayd daemon peer does not allow sessions to be cleared"; | |
379 | case LTTNG_ERR_CLEAR_NOT_AVAILABLE_RELAY: | |
380 | return "Clearing a session is not supported by the relay daemon"; | |
381 | case LTTNG_ERR_CLEAR_FAIL_CONSUMER: | |
382 | return "Consumer failed to clear the session"; | |
383 | case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR: | |
384 | return "Session was already cleared since it became inactive"; | |
385 | case LTTNG_ERR_USER_NOT_FOUND: | |
386 | return "User not found"; | |
387 | case LTTNG_ERR_GROUP_NOT_FOUND: | |
388 | return "Group not found"; | |
389 | case LTTNG_ERR_UNSUPPORTED_DOMAIN: | |
390 | return "Unsupported domain used"; | |
391 | case LTTNG_ERR_PROCESS_ATTR_TRACKER_INVALID_TRACKING_POLICY: | |
392 | return "Operation does not apply to the process attribute tracker's tracking policy"; | |
393 | case LTTNG_ERR_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD: | |
394 | return "Failed to create an event notifier group notification file descriptor"; | |
395 | case LTTNG_ERR_INVALID_CAPTURE_EXPRESSION: | |
396 | return "Invalid capture expression"; | |
397 | case LTTNG_ERR_EVENT_NOTIFIER_REGISTRATION: | |
398 | return "Failed to create event notifier"; | |
399 | case LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING: | |
400 | return "Failed to initialize event notifier error accounting"; | |
401 | case LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL: | |
402 | return "No index available in event notifier error accounting"; | |
403 | case LTTNG_ERR_INVALID_ERROR_QUERY_TARGET: | |
404 | return "Invalid error query target."; | |
405 | case LTTNG_ERR_BUFFER_FLUSH_FAILED: | |
406 | return "Failed to flush stream buffer"; | |
407 | case LTTNG_ERR_NR: | |
408 | abort(); | |
409 | } | |
410 | ||
411 | abort(); | |
412 | }; | |
413 | ||
414 | /* | |
415 | * Return ptr to string representing a human readable error code from the | |
416 | * lttng_error_code enum. | |
417 | * | |
418 | * These code MUST be negative in other to treat that as an error value. | |
419 | */ | |
420 | const char *error_get_str(int32_t code) | |
421 | { | |
422 | code = -code; | |
423 | ||
424 | if (code < LTTNG_OK || code >= LTTNG_ERR_NR) { | |
425 | code = LTTNG_ERR_UNK; | |
426 | } | |
427 | ||
428 | return lttng_error_code_str((lttng_error_code) code); | |
429 | } | |
430 | ||
431 | void lttng_abort_on_error(void) | |
432 | { | |
433 | if (lttng_opt_abort_on_error < 0) { | |
434 | /* Use lttng_secure_getenv() to query its state. */ | |
435 | const char *value; | |
436 | ||
437 | value = lttng_secure_getenv("LTTNG_ABORT_ON_ERROR"); | |
438 | if (value && !strcmp(value, "1")) { | |
439 | lttng_opt_abort_on_error = 1; | |
440 | } else { | |
441 | lttng_opt_abort_on_error = 0; | |
442 | } | |
443 | } | |
444 | if (lttng_opt_abort_on_error > 0) { | |
445 | abort(); | |
446 | } | |
447 | } |