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