1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * S Y S D E P *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2023, Free Software Foundation, Inc. *
10 * *
11 * GNAT is free software; you can redistribute it and/or modify it under *
12 * terms of the GNU General Public License as published by the Free Soft- *
13 * ware Foundation; either version 3, or (at your option) any later ver- *
14 * sion. GNAT is distributed in the hope that it will be useful, but WITH- *
15 * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
16 * or FITNESS FOR A PARTICULAR PURPOSE. *
17 * *
18 * As a special exception under Section 7 of GPL version 3, you are granted *
19 * additional permissions described in the GCC Runtime Library Exception, *
20 * version 3.1, as published by the Free Software Foundation. *
21 * *
22 * You should have received a copy of the GNU General Public License and *
23 * a copy of the GCC Runtime Library Exception along with this program; *
24 * see the files COPYING3 and COPYING.RUNTIME respectively. If not, see *
25 * <http://www.gnu.org/licenses/>. *
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
30 ****************************************************************************/
31
32 /* This file contains system dependent symbols that are referenced in the
33 GNAT Run Time Library */
34
35 #ifdef __vxworks
36 #include "vxWorks.h"
37 #include "ioLib.h"
38 #if ! defined (VTHREADS)
39 #include "dosFsLib.h"
40 #endif
41 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
42 # include "nfsLib.h"
43 #endif
44 #include "selectLib.h"
45 #include "version.h"
46 #if defined (__RTP__)
47 # include "vwModNum.h"
48 #endif /* __RTP__ */
49 #endif
50
51 #ifdef __ANDROID__
52 #undef __linux__
53 #endif
54
55 #ifdef IN_RTS
56 #define POSIX
57 #include "runtime.h"
58 #include <string.h>
59 #include <unistd.h>
60
61 #include <fcntl.h>
62 #include <sys/stat.h>
63 #else
64 #include "config.h"
65 #include "system.h"
66 #endif
67
68 #include <time.h>
69 #include <errno.h>
70
71 #if defined (__sun__) && !defined (__vxworks)
72 /* The declaration is present in <time.h> but conditionalized
73 on a couple of macros we don't define. */
74 extern struct tm *localtime_r(const time_t *, struct tm *);
75 #endif
76
77 #include "adaint.h"
78
79 /* Don't use macros versions of this functions on VxWorks since they cause
80 imcompatible changes in some VxWorks versions */
81 #ifdef __vxworks
82 #undef getchar
83 #undef putchar
84 #undef feof
85 #undef ferror
86 #undef fileno
87 #endif
88
89 /*
90 Notes:
91
92 (1) Opening a file with read mode fails if the file does not exist or
93 cannot be read.
94
95 (2) Opening a file with append mode causes all subsequent writes to the
96 file to be forced to the then current end-of-file, regardless of
97 intervening calls to the fseek function.
98
99 (3) When a file is opened with update mode, both input and output may be
100 performed on the associated stream. However, output may not be directly
101 followed by input without an intervening call to the fflush function or
102 to a file positioning function (fseek, fsetpos, or rewind), and input
103 may not be directly followed by output without an intervening call to a
104 file positioning function, unless the input operation encounters
105 end-of-file.
106
107 The other target dependent declarations here are for the three functions
108 __gnat_set_binary_mode, __gnat_set_text_mode and __gnat_set_mode:
109
110 void __gnat_set_binary_mode (int handle);
111 void __gnat_set_text_mode (int handle);
112 void __gnat_set_mode (int handle, int mode);
113
114 These functions have no effect in Unix (or similar systems where there is
115 no distinction between binary and text files), but in DOS (and similar
116 systems where text mode does CR/LF translation), these functions allow
117 the mode of the stream with the given handle (fileno can be used to get
118 the handle of a stream) to be changed dynamically. The returned result
119 is 0 if no error occurs and -1 if an error occurs.
120
121 Finally there is a boolean (character) variable
122
123 char __gnat_text_translation_required;
124
125 which is zero (false) in Unix mode, and one (true) in DOS mode, with a
126 true value indicating that text translation is required on text files
127 and that fopen supports the trailing t and b modifiers.
128
129 */
130
131 #if defined (WINNT) || defined (__CYGWIN__) || defined (__DJGPP__)
132
133 const char __gnat_text_translation_required = 1;
134
135 #ifdef __CYGWIN__
136 #define WIN_SETMODE setmode
137 #include <io.h>
138 #else
139 #define WIN_SETMODE _setmode
140 #endif
141
142 #if defined (__DJGPP__)
143 #include <io.h>
144 #define _setmode setmode
145 #endif /* __DJGPP__ */
146
147 void
148 __gnat_set_binary_mode (int handle)
149 {
150 WIN_SETMODE (handle, O_BINARY);
151 }
152
153 void
154 __gnat_set_text_mode (int handle)
155 {
156 WIN_SETMODE (handle, O_TEXT);
157 }
158
159 #if defined (__CYGWIN__) || defined (__DJGPP__)
160 void
161 __gnat_set_mode (int handle, int mode)
162 {
163 /* the values here must be synchronized with
164 System.File_Control_Block.Content_Encodding:
165
166 None = 0
167 Default_Text = 1
168 Text = 2
169 U8text = 3
170 Wtext = 4
171 U16text = 5 */
172
173 switch (mode) {
174 case 0 : setmode(handle, O_BINARY); break;
175 case 1 : setmode(handle, O_TEXT); break;
176 case 2 : setmode(handle, O_TEXT); break;
177 case 3 : setmode(handle, O_TEXT); break;
178 case 4 : setmode(handle, O_BINARY); break;
179 case 5 : setmode(handle, O_BINARY); break;
180 }
181 }
182 #else
183 void
184 __gnat_set_mode (int handle, int mode)
185 {
186 /* the values here must be synchronized with
187 System.File_Control_Block.Content_Encodding:
188
189 None = 0
190 Default_Text = 1
191 Text = 2
192 U8text = 3
193 Wtext = 4
194 U16text = 5 */
195
196 switch (mode) {
197 case 0 : WIN_SETMODE (handle, _O_BINARY); break;
198 case 1 : WIN_SETMODE (handle, __gnat_current_ccs_encoding); break;
199 case 2 : WIN_SETMODE (handle, _O_TEXT); break;
200 case 3 : WIN_SETMODE (handle, _O_U8TEXT); break;
201 case 4 : WIN_SETMODE (handle, _O_WTEXT); break;
202 case 5 : WIN_SETMODE (handle, _O_U16TEXT); break;
203 }
204 }
205 #endif
206
207 #ifdef __CYGWIN__
208
209 char *
210 __gnat_ttyname (int filedes)
211 {
212 extern char *ttyname (int);
213
214 return ttyname (filedes);
215 }
216
217 #endif /* __CYGWIN__ */
218
219 #if defined (__CYGWIN__) || defined (__MINGW32__)
220 #define WIN32_LEAN_AND_MEAN
221 #include <windows.h>
222
223 int __gnat_is_windows_xp (void);
224
225 int
226 __gnat_is_windows_xp (void)
227 {
228 static int is_win_xp=0, is_win_xp_checked=0;
229
230 if (!is_win_xp_checked)
231 {
232 OSVERSIONINFO version;
233
234 is_win_xp_checked = 1;
235
236 memset (&version, 0, sizeof (version));
237 version.dwOSVersionInfoSize = sizeof (version);
238
239 is_win_xp = GetVersionEx (&version)
240 && version.dwPlatformId == VER_PLATFORM_WIN32_NT
241 && (version.dwMajorVersion > 5
242 || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1));
243 }
244 return is_win_xp;
245 }
246
247 /* Get the bounds of the stack. The stack pointer is supposed to be
248 initialized to BASE when a thread is created and the stack can be extended
249 to LIMIT before reaching a guard page.
250 Note: for the main thread, the system automatically extend the stack, so
251 LIMIT is only the current limit. */
252
253 void
254 __gnat_get_stack_bounds (void **base, void **limit)
255 {
256 NT_TIB *tib;
257
258 /* We know that the first field of the TEB is the TIB. */
259 tib = (NT_TIB *)NtCurrentTeb ();
260
261 *base = tib->StackBase;
262 *limit = tib->StackLimit;
263 }
264
265 #endif /* __CYGWIN__ || __MINGW32__ */
266
267 #ifdef __MINGW32__
268
269 /* Return the name of the tty. Under windows there is no name for
270 the tty, so this function, if connected to a tty, returns the generic name
271 "console". */
272
273 char *
274 __gnat_ttyname (int filedes)
275 {
276 if (isatty (filedes))
277 return "console";
278 else
279 return NULL;
280 }
281
282 #endif /* __MINGW32__ */
283
284 #else
285
286 const char __gnat_text_translation_required = 0;
287
288 /* These functions do nothing in non-DOS systems. */
289
290 void
291 __gnat_set_binary_mode (int handle ATTRIBUTE_UNUSED)
292 {
293 }
294
295 void
296 __gnat_set_text_mode (int handle ATTRIBUTE_UNUSED)
297 {
298 }
299
300 void
301 __gnat_set_mode (int handle ATTRIBUTE_UNUSED, int mode ATTRIBUTE_UNUSED)
302 {
303 }
304
305 char *
306 __gnat_ttyname (int filedes ATTRIBUTE_UNUSED)
307 {
308 #if defined (__vxworks)
309 return "";
310 #else
311 extern char *ttyname (int);
312
313 return ttyname (filedes);
314 #endif /* defined (__vxworks) */
315 }
316 #endif
317
318 #if defined (__linux__) || defined (__sun__) \
319 || defined (WINNT) \
320 || defined (__MACHTEN__) || defined (__hpux__) || defined (_AIX) \
321 || (defined (__svr4__) && defined (__i386__)) || defined (__Lynx__) \
322 || defined (__CYGWIN__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
323 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
324 || defined (__QNX__)
325
326 # ifdef __MINGW32__
327 # include <conio.h> /* for getch(), kbhit() */
328 # else
329 # include <termios.h>
330 # endif
331
332 #endif
333
334 /* Implements the common processing for getc_immediate and
335 getc_immediate_nowait. */
336
337 extern void getc_immediate (FILE *, int *, int *);
338 extern void getc_immediate_nowait (FILE *, int *, int *, int *);
339 extern void getc_immediate_common (FILE *, int *, int *, int *, int);
340
341 /* Called by Get_Immediate (Foo); */
342
343 void
344 getc_immediate (FILE *stream, int *ch, int *end_of_file)
345 {
346 int avail;
347
348 getc_immediate_common (stream, ch, end_of_file, &avail, 1);
349 }
350
351 /* Called by Get_Immediate (Foo, Available); */
352
353 void
354 getc_immediate_nowait (FILE *stream, int *ch, int *end_of_file, int *avail)
355 {
356 getc_immediate_common (stream, ch, end_of_file, avail, 0);
357 }
358
359 /* Called by getc_immediate () and getc_immediate_nowait () */
360
361 void
362 getc_immediate_common (FILE *stream,
363 int *ch,
364 int *end_of_file,
365 int *avail,
366 int waiting ATTRIBUTE_UNUSED)
367 {
368 #if defined (__linux__) || defined (__sun__) \
369 || defined (__CYGWIN32__) || defined (__MACHTEN__) || defined (__hpux__) \
370 || defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
371 || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
372 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
373 || defined (__QNX__)
374 char c;
375 int nread;
376 int good_one = 0;
377 int eof_ch = 4; /* Ctrl-D */
378 int fd = fileno (stream);
379 struct termios otermios_rec, termios_rec;
380
381 if (isatty (fd))
382 {
383 tcgetattr (fd, &termios_rec);
384 memcpy (&otermios_rec, &termios_rec, sizeof (struct termios));
385
386 /* Set RAW mode, with no echo */
387 termios_rec.c_lflag = termios_rec.c_lflag & ~ICANON & ~ECHO;
388
389 #if defined (__linux__) || defined (__sun__) \
390 || defined (__MACHTEN__) || defined (__hpux__) \
391 || defined (_AIX) || (defined (__svr4__) && defined (__i386__)) \
392 || defined (__Lynx__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
393 || defined (__GLIBC__) || defined (__APPLE__) || defined (__DragonFly__) \
394 || defined (__QNX__)
395 eof_ch = termios_rec.c_cc[VEOF];
396
397 /* If waiting (i.e. Get_Immediate (Char)), set MIN = 1 and wait for
398 a character forever. This doesn't seem to effect Ctrl-Z or
399 Ctrl-C processing.
400 If not waiting (i.e. Get_Immediate (Char, Available)),
401 don't wait for anything but timeout immediately. */
402 termios_rec.c_cc[VMIN] = waiting;
403 termios_rec.c_cc[VTIME] = 0;
404 #endif
405 tcsetattr (fd, TCSANOW, &termios_rec);
406
407 while (! good_one)
408 {
409 /* Read is used here instead of fread, because fread doesn't
410 work on Solaris5 and Sunos4 in this situation. Maybe because we
411 are mixing calls that use file descriptors and streams. */
412 nread = read (fd, &c, 1);
413 if (nread > 0)
414 {
415 /* On Unix terminals, Ctrl-D (EOT) is an End of File. */
416 if (c == eof_ch)
417 {
418 *avail = 0;
419 *end_of_file = 1;
420 good_one = 1;
421 }
422
423 /* Everything else is ok */
424 else if (c != eof_ch)
425 {
426 *avail = 1;
427 *end_of_file = 0;
428 good_one = 1;
429 }
430 }
431
432 else if (! waiting)
433 {
434 *avail = 0;
435 *end_of_file = 0;
436 good_one = 1;
437 }
438 else
439 good_one = 0;
440 }
441
442 tcsetattr (fd, TCSANOW, &otermios_rec);
443 *ch = c;
444 }
445
446 else
447 #elif defined (__MINGW32__)
448 int fd = fileno (stream);
449 int char_waiting;
450 int eot_ch = 4; /* Ctrl-D */
451
452 if (isatty (fd))
453 {
454 if (waiting)
455 {
456 *ch = getch ();
457
458 if (*ch == eot_ch)
459 *end_of_file = 1;
460 else
461 *end_of_file = 0;
462
463 *avail = 1;
464 }
465 else /* ! waiting */
466 {
467 char_waiting = kbhit();
468
469 if (char_waiting == 1)
470 {
471 *avail = 1;
472 *ch = getch ();
473
474 if (*ch == eot_ch)
475 *end_of_file = 1;
476 else
477 *end_of_file = 0;
478 }
479 else
480 {
481 *avail = 0;
482 *end_of_file = 0;
483 }
484 }
485 }
486 else
487 #elif defined (__vxworks)
488 /* Bit masks of file descriptors to read from. */
489 struct fd_set readFds;
490 /* Timeout before select returns if nothing can be read. */
491 struct timeval timeOut;
492 char c;
493 int fd = fileno (stream);
494 int nread;
495 int option;
496 int readable;
497 int status;
498 int width;
499
500 if (isatty (fd))
501 {
502 /* If we do not want to wait, we have to set up fd in RAW mode. This
503 should be done outside this function as setting fd in RAW mode under
504 vxWorks flushes the buffer of fd. If the RAW mode was set here, the
505 buffer would be empty and we would always return that no character
506 is available */
507 if (! waiting)
508 {
509 /* Initialization of timeOut for its use with select. */
510 timeOut.tv_sec = 0;
511 timeOut.tv_usec = 0;
512
513 /* Initialization of readFds for its use with select;
514 FD is the only file descriptor to be monitored */
515 FD_ZERO (&readFds);
516 FD_SET (fd, &readFds);
517 width = 2;
518
519 /* We do all this processing to emulate a non blocking read. */
520 readable = select (width, &readFds, NULL, NULL, &timeOut);
521 if (readable == ERROR)
522 *avail = -1, *end_of_file = -1;
523 /* No character available in input. */
524 else if (readable == 0)
525 *avail = 0, *end_of_file = 0;
526 else
527 {
528 nread = read (fd, &c, 1);
529 if (nread > 0)
530 *avail = 1, *end_of_file = 0;
531 /* End Of File. */
532 else if (nread == 0)
533 *avail = 0, *end_of_file = 1;
534 /* Error. */
535 else
536 *avail = -1, *end_of_file = -1;
537 }
538 }
539
540 /* We have to wait until we get a character */
541 else
542 {
543 *avail = -1;
544 *end_of_file = -1;
545
546 /* Save the current mode of FD. */
547 option = ioctl (fd, FIOGETOPTIONS, 0);
548
549 /* Set FD in RAW mode. */
550 status = ioctl (fd, FIOSETOPTIONS, OPT_RAW);
551 if (status != -1)
552 {
553 nread = read (fd, &c, 1);
554 if (nread > 0)
555 *avail = 1, *end_of_file = 0;
556 /* End of file. */
557 else if (nread == 0)
558 *avail = 0, *end_of_file = 1;
559 /* Else there is an ERROR. */
560 }
561
562 /* Revert FD to its previous mode. */
563 status = ioctl (fd, FIOSETOPTIONS, option);
564 }
565
566 *ch = c;
567 }
568 else
569 #endif
570 {
571 /* If we're not on a terminal, then we don't need any fancy processing.
572 Also this is the only thing that's left if we're not on one of the
573 supported systems; which means that for non supported systems,
574 get_immediate may wait for a carriage return on terminals. */
575 *ch = fgetc (stream);
576 if (feof (stream))
577 {
578 *end_of_file = 1;
579 *avail = 0;
580 }
581 else
582 {
583 *end_of_file = 0;
584 *avail = 1;
585 }
586 }
587 }
588
589 /* The following definitions are provided in NT to support Windows based
590 Ada programs. */
591
592 #ifdef WINNT
593 #define WIN32_LEAN_AND_MEAN
594 #include <windows.h>
595
596 /* Provide functions to echo the values passed to WinMain (windows bindings
597 will want to import these). We use the same names as the routines used
598 by AdaMagic for compatibility. */
599
600 char *rts_get_hInstance (void);
601 char *rts_get_hPrevInstance (void);
602 char *rts_get_lpCommandLine (void);
603 int rts_get_nShowCmd (void);
604
605 char *
606 rts_get_hInstance (void)
607 {
608 return (char *)GetModuleHandleA (0);
609 }
610
611 char *
612 rts_get_hPrevInstance (void)
613 {
614 return 0;
615 }
616
617 char *
618 rts_get_lpCommandLine (void)
619 {
620 return GetCommandLineA ();
621 }
622
623 int
624 rts_get_nShowCmd (void)
625 {
626 return 1;
627 }
628
629 #endif /* WINNT */
630
631 /* This value is returned as the time zone offset when a valid value
632 cannot be determined. It is simply a bizarre value that will never
633 occur. It is 3 days plus 73 seconds (offset is in seconds). */
634
635 long __gnat_invalid_tzoff = 259273;
636
637 /* Definition of __gnat_localtime_r used by a-calend.adb */
638
639 #if defined (__MINGW32__)
640
641 /* Reentrant localtime for Windows. */
642
643 extern void
644 __gnat_localtime_tzoff (const OS_Time *, const int *, long *);
645
646 static const unsigned long long w32_epoch_offset = 11644473600ULL;
647 void
648 __gnat_localtime_tzoff (const OS_Time *timer, const int *is_historic, long *off)
649 {
650 TIME_ZONE_INFORMATION tzi;
651
652 DWORD tzi_status;
653
654 tzi_status = GetTimeZoneInformation (&tzi);
655
656 /* Cases where we simply want to extract the offset of the current time
657 zone, regardless of the date. A value of "0" for flag "is_historic"
658 signifies that the date is NOT historic, see the
659 body of Ada.Calendar.UTC_Time_Offset. */
660
661 if (*is_historic == 0) {
662 *off = tzi.Bias;
663
664 /* The system is operating in the range covered by the StandardDate
665 member. */
666 if (tzi_status == TIME_ZONE_ID_STANDARD) {
667 *off = *off + tzi.StandardBias;
668 }
669
670 /* The system is operating in the range covered by the DaylightDate
671 member. */
672 else if (tzi_status == TIME_ZONE_ID_DAYLIGHT) {
673 *off = *off + tzi.DaylightBias;
674 }
675
676 *off = *off * -60;
677 }
678
679 /* Time zone offset calculations for a historic or future date */
680
681 else {
682 union
683 {
684 FILETIME ft_time;
685 unsigned long long ull_time;
686 } utc_time, local_time;
687
688 SYSTEMTIME utc_sys_time, local_sys_time;
689 BOOL status;
690
691 /* First convert unix time_t structure to windows FILETIME format. */
692 utc_time.ull_time = ((unsigned long long) *timer + w32_epoch_offset)
693 * 10000000ULL;
694
695 /* If GetTimeZoneInformation does not return a value between 0 and 2 then
696 it means that we were not able to retrieve timezone information. Note
697 that we cannot use here FileTimeToLocalFileTime as Windows will use in
698 always in this case the current timezone setting. As suggested on MSDN
699 we use the following three system calls to get the right information.
700 Note also that starting with Windows Vista new functions are provided
701 to get timezone settings that depend on the year. We cannot use them as
702 we still support Windows XP and Windows 2003. */
703
704 status = tzi_status <= 2
705 && FileTimeToSystemTime (&utc_time.ft_time, &utc_sys_time)
706 && SystemTimeToTzSpecificLocalTime (&tzi, &utc_sys_time, &local_sys_time)
707 && SystemTimeToFileTime (&local_sys_time, &local_time.ft_time);
708
709 /* An error has occurred, return invalid_tzoff */
710
711 if (!status) {
712 *off = __gnat_invalid_tzoff;
713 }
714 else {
715 if (local_time.ull_time > utc_time.ull_time) {
716 *off = (long) ((local_time.ull_time - utc_time.ull_time)
717 / 10000000ULL);
718 }
719 else {
720 *off = - (long) ((utc_time.ull_time - local_time.ull_time)
721 / 10000000ULL);
722 }
723 }
724 }
725 }
726
727 #elif defined (__Lynx__)
728
729 /* On Lynx, all time values are treated in GMT */
730
731 /* As of LynxOS 3.1.0a patch level 040, LynuxWorks changes the
732 prototype to the C library function localtime_r from the POSIX.4
733 Draft 9 to the POSIX 1.c version. Before this change the following
734 spec is required. Only use when ___THREADS_POSIX4ad4__ is defined,
735 the Lynx convention when building against the legacy API. */
736
737 extern void
738 __gnat_localtime_tzoff (const OS_Time *, const int *, long *);
739
740 void
741 __gnat_localtime_tzoff (const OS_Time *timer, const int *is_historic, long *off)
742 {
743 *off = 0;
744 }
745
746 #else
747
748 /* Other targets except Lynx and Windows provide a standard localtime_r */
749
750 #define Lock_Task system__soft_links__lock_task
751 extern void (*Lock_Task) (void);
752
753 #define Unlock_Task system__soft_links__unlock_task
754 extern void (*Unlock_Task) (void);
755
756 extern void
757 __gnat_localtime_tzoff (const OS_Time *, const int *, long *);
758
759 void
760 __gnat_localtime_tzoff (const OS_Time *timer ATTRIBUTE_UNUSED,
761 const int *is_historic ATTRIBUTE_UNUSED,
762 long *off ATTRIBUTE_UNUSED)
763 {
764 struct tm tp ATTRIBUTE_UNUSED;
765 const time_t time = (time_t) *timer;
766
767 /* AIX, HPUX, Sun Solaris */
768 #if defined (_AIX) || defined (__hpux__) || defined (__sun__)
769 {
770 (*Lock_Task) ();
771
772 localtime_r (&time, &tp);
773 *off = (long) -timezone;
774
775 (*Unlock_Task) ();
776
777 /* Correct the offset if Daylight Saving Time is in effect */
778
779 if (tp.tm_isdst > 0)
780 *off = *off + 3600;
781 }
782
783 /* VxWorks */
784 #elif defined (__vxworks)
785 #include <stdlib.h>
786 {
787 (*Lock_Task) ();
788
789 localtime_r (&time, &tp);
790
791 /* Try to read the environment variable TIMEZONE. The variable may not have
792 been initialize, in that case return an offset of zero (0) for UTC. */
793
794 char *tz_str = getenv ("TIMEZONE");
795
796 if ((tz_str == NULL) || (*tz_str == '\0'))
797 *off = 0;
798 else
799 {
800 char *tz_start, *tz_end;
801
802 /* The format of the data contained in TIMEZONE is N::U:S:E where N is the
803 name of the time zone, U are the minutes difference from UTC, S is the
804 start of DST in mmddhh and E is the end of DST in mmddhh. Extracting
805 the value of U involves setting two pointers, one at the beginning and
806 one at the end of the value. The end pointer is then set to null in
807 order to delimit a string slice for atol to process. */
808
809 tz_start = index (tz_str, ':') + 2;
810 tz_end = index (tz_start, ':');
811 *tz_end = '\0';
812
813 /* The Ada layer expects an offset in seconds. Note that we must reverse
814 the sign of the result since west is positive and east is negative on
815 VxWorks targets. */
816
817 *off = -atol (tz_start) * 60;
818
819 /* Correct the offset if Daylight Saving Time is in effect */
820
821 if (tp.tm_isdst > 0)
822 *off = *off + 3600;
823 }
824
825 (*Unlock_Task) ();
826 }
827
828 /* Darwin, Free BSD, Linux, where component tm_gmtoff is present in
829 struct tm */
830
831 #elif defined (__APPLE__) || defined (__FreeBSD__) || defined (__linux__) \
832 || defined (__GLIBC__) || defined (__DragonFly__) || defined (__OpenBSD__) \
833 || defined (__DJGPP__) || defined (__QNX__)
834 {
835 localtime_r (&time, &tp);
836 *off = tp.tm_gmtoff;
837 }
838
839 /* Default: treat all time values in GMT */
840
841 #else
842 *off = 0;
843
844 #endif /* defined(_AIX) ... */
845 }
846
847 #endif
848
849 #ifdef __vxworks
850
851 #include <taskLib.h>
852
853 /* __gnat_get_task_options is used by s-taprop.adb only for VxWorks. This
854 function returns the options to be set when creating a new task. It fetches
855 the options assigned to the current task (parent), so offering some user
856 level control over the options for a task hierarchy. It forces VX_FP_TASK
857 because it is almost always required. On processors with the SPE
858 category, VX_SPE_TASK should be used instead to enable the SPE. */
859 extern int __gnat_get_task_options (void);
860
861 int
862 __gnat_get_task_options (void)
863 {
864 int options;
865
866 /* Get the options for the task creator */
867 taskOptionsGet (taskIdSelf (), &options);
868
869 /* Force VX_FP_TASK or VX_SPE_TASK as needed */
870 #if defined (__SPE__)
871 options |= VX_SPE_TASK;
872 #else
873 options |= VX_FP_TASK;
874 #endif
875
876 /* Mask those bits that are not under user control */
877 #ifdef VX_USR_TASK_OPTIONS
878 /* O810-007, TSR 00043679:
879 Workaround a bug in Vx-7 where VX_DEALLOC_TCB == VX_PRIVATE_UMASK and:
880 - VX_DEALLOC_TCB is an internal option not to be used by users
881 - VX_PRIVATE_UMASK as a user-definable option
882 This leads to VX_USR_TASK_OPTIONS allowing 0x8000 as VX_PRIVATE_UMASK but
883 taskCreate refusing this option (VX_DEALLOC_TCB is not allowed)
884
885 Note that the same error occurs in both RTP and Kernel mode, but
886 VX_DEALLOC_TCB is not defined in the RTP headers, so we need to
887 explicitely check if VX_PRIVATE_UMASK has value 0x8000
888 */
889 # if defined (VX_PRIVATE_UMASK) && (0x8000 == VX_PRIVATE_UMASK)
890 options &= ~VX_PRIVATE_UMASK;
891 # endif
892 options &= VX_USR_TASK_OPTIONS;
893 #endif
894 return options;
895 }
896
897 #endif
898
899 int
900 __gnat_is_file_not_found_error (int errno_val)
901 {
902 /* WARNING: Do not rewrite this as a switch/case statement.
903 * Some of the "cases" are duplicated in some versions of
904 * Vxworks, notably VxWorks7r2 SR0610. */
905 if (errno_val == ENOENT)
906 return 1;
907 #ifdef __vxworks
908 /* Starting with VxWorks 21.03, the fopen() function can set errno to
909 * ENODEV when the prefix of the path does not match any known device. */
910 else if (errno_val == ENODEV)
911 return 1;
912 /* In the case of VxWorks, we also have to take into account various
913 * filesystem-specific variants of this error.
914 */
915 #if ! defined (VTHREADS) && (_WRS_VXWORKS_MAJOR < 7)
916 else if (errno_val == S_dosFsLib_FILE_NOT_FOUND)
917 return 1;
918 #endif
919 #if ! defined (__RTP__) && (! defined (VTHREADS) || defined (__VXWORKSMILS__))
920 else if (errno_val == S_nfsLib_NFSERR_NOENT)
921 return 1;
922 #endif
923 #if defined (__RTP__)
924 /* An RTP can return an NFS file not found, and the NFS bits must
925 first be masked on to check the errno. */
926 else if (errno_val == (M_nfsStat | ENOENT))
927 return 1;
928 #endif
929 #endif
930 else
931 return 0;
932 }
933
934 #if defined (__linux__)
935
936 /* Note well: If this code is modified, it should be tested by hand,
937 because automated testing doesn't exercise it.
938 */
939
940 /* HAVE_CAPABILITY is supposed to be defined if sys/capability.h exists on the
941 system where this is being compiled. If this macro is defined, we #include
942 the header. Otherwise we have the relevant declarations textually here.
943 */
944
945 #if defined (HAVE_CAPABILITY)
946 #include <sys/capability.h>
947 #else
948
949 /* HAVE_CAPABILITY is not defined, so sys/capability.h does might not exist. */
950
951 typedef struct _cap_struct *cap_t;
952 typedef enum {
953 CAP_CLEAR=0,
954 CAP_SET=1
955 } cap_flag_value_t;
956 #define CAP_SYS_NICE 23
957 typedef enum {
958 CAP_EFFECTIVE=0, /* Specifies the effective flag */
959 CAP_PERMITTED=1, /* Specifies the permitted flag */
960 CAP_INHERITABLE=2 /* Specifies the inheritable flag */
961 } cap_flag_t;
962
963 typedef int cap_value_t;
964
965 extern cap_t cap_get_proc(void);
966 extern int cap_get_flag(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *);
967 extern int cap_free(void *);
968
969 #endif
970
971 /* __gnat_has_cap_sys_nice returns 1 if the current process has the
972 CAP_SYS_NICE capability. This capability is necessary to use the
973 Ceiling_Locking policy. Returns 0 otherwise. Note that this is
974 defined only for Linux.
975 */
976
977 /* Define these as weak symbols, so if support for capabilities is not present,
978 programs can still link. On Ubuntu, support for capabilities can be
979 installed via "sudo apt-get --assume-yes install libcap-dev".
980 In addition, the user must link with "-lcap", or else these
981 symbols will be 0, and __gnat_has_cap_sys_nice will return 0.
982 */
983
984 static cap_t cap_get_proc_weak(void)
985 __attribute__ ((weakref ("cap_get_proc")));
986 static int cap_get_flag_weak(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *)
987 __attribute__ ((weakref ("cap_get_flag")));
988 static int cap_free_weak(void *)
989 __attribute__ ((weakref ("cap_free")));
990
991 int
992 __gnat_has_cap_sys_nice () {
993 /* If the address of cap_get_proc_weak is 0, this means support for
994 capabilities is not present, so we return 0. */
995 if (&cap_get_proc_weak == 0)
996 return 0;
997
998 cap_t caps = cap_get_proc_weak();
999 if (caps == NULL)
1000 return 0;
1001
1002 cap_flag_value_t value;
1003
1004 if (cap_get_flag_weak(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &value) == -1)
1005 return 0;
1006
1007 if (cap_free_weak(caps) == -1)
1008 return 0;
1009
1010 if (value == CAP_SET)
1011 return 1;
1012
1013 return 0;
1014 }
1015 #endif
1016
1017 #ifdef __ANDROID__
1018
1019 /* Provide extern symbols for sig* as needed by the tasking run-time, instead
1020 of static inline functions. */
1021
1022 #include <signal.h>
1023
1024 int
1025 _sigismember (sigset_t *set, int signum)
1026 {
1027 return sigismember (set, signum);
1028 }
1029
1030 int
1031 _sigaddset (sigset_t *set, int signum)
1032 {
1033 return sigaddset (set, signum);
1034 }
1035
1036 int
1037 _sigdelset (sigset_t *set, int signum)
1038 {
1039 return sigdelset (set, signum);
1040 }
1041
1042 int
1043 _sigemptyset (sigset_t *set)
1044 {
1045 return sigemptyset (set);
1046 }
1047
1048 int
1049 _sigfillset (sigset_t *set)
1050 {
1051 return sigfillset (set);
1052 }
1053
1054 #include <unistd.h>
1055 int
1056 _getpagesize (void)
1057 {
1058 return getpagesize ();
1059 }
1060 #endif
1061
1062 int
1063 __gnat_name_case_equivalence ()
1064 {
1065 /* the values here must be synchronized with Ada.Directories.Name_Case_Kind:
1066
1067 Unknown = 0
1068 Case_Sensitive = 1
1069 Case_Insensitive = 2
1070 Case_Preserving = 3 */
1071
1072 #if defined (__APPLE__) || defined (WIN32)
1073 return 3;
1074 #else
1075 return 1;
1076 #endif
1077 }