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