PR target/79080
[official-gcc.git] / gcc / ada / adaint.c
blob54a1d6e25c3196bd5ac91d190d5ba964545fd913
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * A D A I N T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 1992-2015, 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 ****************************************************************************/
32 /* This file contains those routines named by Import pragmas in
33 packages in the GNAT hierarchy (especially GNAT.OS_Lib) and in
34 package Osint. Many of the subprograms in OS_Lib import standard
35 library calls directly. This file contains all other routines. */
37 /* Ensure access to errno is thread safe. */
38 #define _REENTRANT
39 #define _THREAD_SAFE
41 /* Use 64 bit Large File API */
42 #ifndef _LARGEFILE_SOURCE
43 #define _LARGEFILE_SOURCE
44 #endif
45 #define _FILE_OFFSET_BITS 64
47 #ifdef __vxworks
49 /* No need to redefine exit here. */
50 #undef exit
52 /* We want to use the POSIX variants of include files. */
53 #define POSIX
54 #include "vxWorks.h"
56 #if defined (__mips_vxworks)
57 #include "cacheLib.h"
58 #endif /* __mips_vxworks */
60 /* If SMP, access vxCpuConfiguredGet */
61 #ifdef _WRS_CONFIG_SMP
62 #include <vxCpuLib.h>
63 #endif /* _WRS_CONFIG_SMP */
65 /* We need to know the VxWorks version because some file operations
66 (such as chmod) are only available on VxWorks 6. */
67 #include "version.h"
69 #endif /* VxWorks */
71 #if defined (__APPLE__)
72 #include <unistd.h>
73 #endif
75 #if defined (__hpux__)
76 #include <sys/param.h>
77 #include <sys/pstat.h>
78 #endif
80 #ifdef __PikeOS__
81 #define __BSD_VISIBLE 1
82 #endif
84 #ifdef IN_RTS
85 #include "tconfig.h"
86 #include "tsystem.h"
87 #include <sys/stat.h>
88 #include <fcntl.h>
89 #include <time.h>
91 #if defined (__vxworks) || defined (__ANDROID__)
92 /* S_IREAD and S_IWRITE are not defined in VxWorks or Android */
93 #ifndef S_IREAD
94 #define S_IREAD (S_IRUSR | S_IRGRP | S_IROTH)
95 #endif
97 #ifndef S_IWRITE
98 #define S_IWRITE (S_IWUSR)
99 #endif
100 #endif
102 /* We don't have libiberty, so use malloc. */
103 #define xmalloc(S) malloc (S)
104 #define xrealloc(V,S) realloc (V,S)
105 #else
106 #include "config.h"
107 #include "system.h"
108 #include "version.h"
109 #endif
111 #ifdef __cplusplus
112 extern "C" {
113 #endif
115 #if defined (__DJGPP__)
117 /* For isalpha-like tests in the compiler, we're expected to resort to
118 safe-ctype.h/ISALPHA. This isn't available for the runtime library
119 build, so we fallback on ctype.h/isalpha there. */
121 #ifdef IN_RTS
122 #include <ctype.h>
123 #define ISALPHA isalpha
124 #endif
126 #elif defined (__MINGW32__) || defined (__CYGWIN__)
128 #include "mingw32.h"
130 /* Current code page and CCS encoding to use, set in initialize.c. */
131 UINT __gnat_current_codepage;
132 UINT __gnat_current_ccs_encoding;
134 #include <sys/utime.h>
136 /* For isalpha-like tests in the compiler, we're expected to resort to
137 safe-ctype.h/ISALPHA. This isn't available for the runtime library
138 build, so we fallback on ctype.h/isalpha there. */
140 #ifdef IN_RTS
141 #include <ctype.h>
142 #define ISALPHA isalpha
143 #endif
145 #elif defined (__Lynx__)
147 /* Lynx utime.h only defines the entities of interest to us if
148 defined (VMOS_DEV), so ... */
149 #define VMOS_DEV
150 #include <utime.h>
151 #undef VMOS_DEV
153 #else
154 #include <utime.h>
155 #endif
157 /* wait.h processing */
158 #ifdef __MINGW32__
159 # if OLD_MINGW
160 # include <sys/wait.h>
161 # endif
162 #elif defined (__vxworks) && defined (__RTP__)
163 # include <wait.h>
164 #elif defined (__Lynx__)
165 /* ??? We really need wait.h and it includes resource.h on Lynx. GCC
166 has a resource.h header as well, included instead of the lynx
167 version in our setup, causing lots of errors. We don't really need
168 the lynx contents of this file, so just workaround the issue by
169 preventing the inclusion of the GCC header from doing anything. */
170 # define GCC_RESOURCE_H
171 # include <sys/wait.h>
172 #elif defined (__PikeOS__)
173 /* No wait() or waitpid() calls available. */
174 #else
175 /* Default case. */
176 #include <sys/wait.h>
177 #endif
179 #if defined (__DJGPP__)
180 #include <process.h>
181 #include <signal.h>
182 #include <dir.h>
183 #include <utime.h>
184 #undef DIR_SEPARATOR
185 #define DIR_SEPARATOR '\\'
187 #elif defined (_WIN32)
189 #include <windows.h>
190 #include <accctrl.h>
191 #include <aclapi.h>
192 #include <tlhelp32.h>
193 #include <signal.h>
194 #undef DIR_SEPARATOR
195 #define DIR_SEPARATOR '\\'
197 #else
198 #include <utime.h>
199 #endif
201 #include "adaint.h"
203 /* Define symbols O_BINARY and O_TEXT as harmless zeroes if they are not
204 defined in the current system. On DOS-like systems these flags control
205 whether the file is opened/created in text-translation mode (CR/LF in
206 external file mapped to LF in internal file), but in Unix-like systems,
207 no text translation is required, so these flags have no effect. */
209 #ifndef O_BINARY
210 #define O_BINARY 0
211 #endif
213 #ifndef O_TEXT
214 #define O_TEXT 0
215 #endif
217 #ifndef HOST_EXECUTABLE_SUFFIX
218 #define HOST_EXECUTABLE_SUFFIX ""
219 #endif
221 #ifndef HOST_OBJECT_SUFFIX
222 #define HOST_OBJECT_SUFFIX ".o"
223 #endif
225 #ifndef PATH_SEPARATOR
226 #define PATH_SEPARATOR ':'
227 #endif
229 #ifndef DIR_SEPARATOR
230 #define DIR_SEPARATOR '/'
231 #endif
233 /* Check for cross-compilation. */
234 #if defined (CROSS_COMPILE) || defined (CROSS_DIRECTORY_STRUCTURE)
235 #define IS_CROSS 1
236 int __gnat_is_cross_compiler = 1;
237 #else
238 #undef IS_CROSS
239 int __gnat_is_cross_compiler = 0;
240 #endif
242 char __gnat_dir_separator = DIR_SEPARATOR;
244 char __gnat_path_separator = PATH_SEPARATOR;
246 /* The GNAT_LIBRARY_TEMPLATE contains a list of expressions that define
247 the base filenames that libraries specified with -lsomelib options
248 may have. This is used by GNATMAKE to check whether an executable
249 is up-to-date or not. The syntax is
251 library_template ::= { pattern ; } pattern NUL
252 pattern ::= [ prefix ] * [ postfix ]
254 These should only specify names of static libraries as it makes
255 no sense to determine at link time if dynamic-link libraries are
256 up to date or not. Any libraries that are not found are supposed
257 to be up-to-date:
259 * if they are needed but not present, the link
260 will fail,
262 * otherwise they are libraries in the system paths and so
263 they are considered part of the system and not checked
264 for that reason.
266 ??? This should be part of a GNAT host-specific compiler
267 file instead of being included in all user applications
268 as well. This is only a temporary work-around for 3.11b. */
270 #ifndef GNAT_LIBRARY_TEMPLATE
271 #define GNAT_LIBRARY_TEMPLATE "lib*.a"
272 #endif
274 const char *__gnat_library_template = GNAT_LIBRARY_TEMPLATE;
276 #if defined (__vxworks)
277 #define GNAT_MAX_PATH_LEN PATH_MAX
279 #else
281 #if defined (__MINGW32__)
282 #include "mingw32.h"
284 #if OLD_MINGW
285 #include <sys/param.h>
286 #endif
288 #else
289 #include <sys/param.h>
290 #endif
292 #ifdef MAXPATHLEN
293 #define GNAT_MAX_PATH_LEN MAXPATHLEN
294 #else
295 #define GNAT_MAX_PATH_LEN 256
296 #endif
298 #endif
300 /* Used for runtime check that Ada constant File_Attributes_Size is no
301 less than the actual size of struct file_attributes (see Osint
302 initialization). */
303 int __gnat_size_of_file_attributes = sizeof (struct file_attributes);
305 void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr);
307 /* The __gnat_max_path_len variable is used to export the maximum
308 length of a path name to Ada code. max_path_len is also provided
309 for compatibility with older GNAT versions, please do not use
310 it. */
312 int __gnat_max_path_len = GNAT_MAX_PATH_LEN;
313 int max_path_len = GNAT_MAX_PATH_LEN;
315 /* Control whether we can use ACL on Windows. */
317 int __gnat_use_acl = 1;
319 /* The following macro HAVE_READDIR_R should be defined if the
320 system provides the routine readdir_r.
321 ... but we never define it anywhere??? */
322 #undef HAVE_READDIR_R
324 #define MAYBE_TO_PTR32(argv) argv
326 static const char ATTR_UNSET = 127;
328 /* Reset the file attributes as if no system call had been performed */
330 void
331 __gnat_reset_attributes (struct file_attributes* attr)
333 attr->exists = ATTR_UNSET;
334 attr->error = EINVAL;
336 attr->writable = ATTR_UNSET;
337 attr->readable = ATTR_UNSET;
338 attr->executable = ATTR_UNSET;
340 attr->regular = ATTR_UNSET;
341 attr->symbolic_link = ATTR_UNSET;
342 attr->directory = ATTR_UNSET;
344 attr->timestamp = (OS_Time)-2;
345 attr->file_length = -1;
349 __gnat_error_attributes (struct file_attributes *attr) {
350 return attr->error;
353 OS_Time
354 __gnat_current_time (void)
356 time_t res = time (NULL);
357 return (OS_Time) res;
360 /* Return the current local time as a string in the ISO 8601 format of
361 "YYYY-MM-DD HH:MM:SS.SS". The returned string is 22 + 1 (NULL) characters
362 long. */
364 void
365 __gnat_current_time_string (char *result)
367 const char *format = "%Y-%m-%d %H:%M:%S";
368 /* Format string necessary to describe the ISO 8601 format */
370 const time_t t_val = time (NULL);
372 strftime (result, 22, format, localtime (&t_val));
373 /* Convert the local time into a string following the ISO format, copying
374 at most 22 characters into the result string. */
376 result [19] = '.';
377 result [20] = '0';
378 result [21] = '0';
379 /* The sub-seconds are manually set to zero since type time_t lacks the
380 precision necessary for nanoseconds. */
383 void
384 __gnat_to_gm_time (OS_Time *p_time, int *p_year, int *p_month, int *p_day,
385 int *p_hours, int *p_mins, int *p_secs)
387 struct tm *res;
388 time_t time = (time_t) *p_time;
390 #ifdef _WIN32
391 /* On Windows systems, the time is sometimes rounded up to the nearest
392 even second, so if the number of seconds is odd, increment it. */
393 if (time & 1)
394 time++;
395 #endif
397 res = gmtime (&time);
398 if (res)
400 *p_year = res->tm_year;
401 *p_month = res->tm_mon;
402 *p_day = res->tm_mday;
403 *p_hours = res->tm_hour;
404 *p_mins = res->tm_min;
405 *p_secs = res->tm_sec;
407 else
408 *p_year = *p_month = *p_day = *p_hours = *p_mins = *p_secs = 0;
411 void
412 __gnat_to_os_time (OS_Time *p_time, int year, int month, int day,
413 int hours, int mins, int secs)
415 struct tm v;
417 v.tm_year = year;
418 v.tm_mon = month;
419 v.tm_mday = day;
420 v.tm_hour = hours;
421 v.tm_min = mins;
422 v.tm_sec = secs;
423 v.tm_isdst = -1;
425 /* returns -1 of failing, this is s-os_lib Invalid_Time */
427 *p_time = (OS_Time) mktime (&v);
430 /* Place the contents of the symbolic link named PATH in the buffer BUF,
431 which has size BUFSIZ. If PATH is a symbolic link, then return the number
432 of characters of its content in BUF. Otherwise, return -1.
433 For systems not supporting symbolic links, always return -1. */
436 __gnat_readlink (char *path ATTRIBUTE_UNUSED,
437 char *buf ATTRIBUTE_UNUSED,
438 size_t bufsiz ATTRIBUTE_UNUSED)
440 #if defined (_WIN32) \
441 || defined(__vxworks) || defined (__PikeOS__)
442 return -1;
443 #else
444 return readlink (path, buf, bufsiz);
445 #endif
448 /* Creates a symbolic link named NEWPATH which contains the string OLDPATH.
449 If NEWPATH exists it will NOT be overwritten.
450 For systems not supporting symbolic links, always return -1. */
453 __gnat_symlink (char *oldpath ATTRIBUTE_UNUSED,
454 char *newpath ATTRIBUTE_UNUSED)
456 #if defined (_WIN32) \
457 || defined(__vxworks) || defined (__PikeOS__)
458 return -1;
459 #else
460 return symlink (oldpath, newpath);
461 #endif
464 /* Try to lock a file, return 1 if success. */
466 #if defined (__vxworks) \
467 || defined (_WIN32) || defined (__PikeOS__)
469 /* Version that does not use link. */
472 __gnat_try_lock (char *dir, char *file)
474 int fd;
475 #ifdef __MINGW32__
476 TCHAR wfull_path[GNAT_MAX_PATH_LEN];
477 TCHAR wfile[GNAT_MAX_PATH_LEN];
478 TCHAR wdir[GNAT_MAX_PATH_LEN];
480 S2WSC (wdir, dir, GNAT_MAX_PATH_LEN);
481 S2WSC (wfile, file, GNAT_MAX_PATH_LEN);
483 /* ??? the code below crash on MingW64 for obscure reasons, a ticket
484 has been opened here:
486 https://sourceforge.net/p/mingw-w64/bugs/414/
488 As a workaround an equivalent set of code has been put in place below.
490 _stprintf (wfull_path, _T("%s%c%s"), wdir, _T(DIR_SEPARATOR), wfile);
493 _tcscpy (wfull_path, wdir);
494 _tcscat (wfull_path, L"\\");
495 _tcscat (wfull_path, wfile);
497 fd = _topen (wfull_path, O_CREAT | O_EXCL, 0600);
498 #else
499 char full_path[256];
501 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
502 fd = open (full_path, O_CREAT | O_EXCL, 0600);
503 #endif
505 if (fd < 0)
506 return 0;
508 close (fd);
509 return 1;
512 #else
514 /* Version using link(), more secure over NFS. */
515 /* See TN 6913-016 for discussion ??? */
518 __gnat_try_lock (char *dir, char *file)
520 char full_path[256];
521 char temp_file[256];
522 GNAT_STRUCT_STAT stat_result;
523 int fd;
525 sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
526 sprintf (temp_file, "%s%cTMP-%ld-%ld",
527 dir, DIR_SEPARATOR, (long)getpid(), (long)getppid ());
529 /* Create the temporary file and write the process number. */
530 fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
531 if (fd < 0)
532 return 0;
534 close (fd);
536 /* Link it with the new file. */
537 link (temp_file, full_path);
539 /* Count the references on the old one. If we have a count of two, then
540 the link did succeed. Remove the temporary file before returning. */
541 __gnat_stat (temp_file, &stat_result);
542 unlink (temp_file);
543 return stat_result.st_nlink == 2;
545 #endif
547 /* Return the maximum file name length. */
550 __gnat_get_maximum_file_name_length (void)
552 return -1;
555 /* Return nonzero if file names are case sensitive. */
557 static int file_names_case_sensitive_cache = -1;
560 __gnat_get_file_names_case_sensitive (void)
562 if (file_names_case_sensitive_cache == -1)
564 const char *sensitive = getenv ("GNAT_FILE_NAME_CASE_SENSITIVE");
566 if (sensitive != NULL
567 && (sensitive[0] == '0' || sensitive[0] == '1')
568 && sensitive[1] == '\0')
569 file_names_case_sensitive_cache = sensitive[0] - '0';
570 else
572 /* By default, we suppose filesystems aren't case sensitive on
573 Windows and Darwin (but they are on arm-darwin). */
574 #if defined (WINNT) || defined (__DJGPP__) \
575 || (defined (__APPLE__) && !(defined (__arm__) || defined (__arm64__)))
576 file_names_case_sensitive_cache = 0;
577 #else
578 file_names_case_sensitive_cache = 1;
579 #endif
582 return file_names_case_sensitive_cache;
585 /* Return nonzero if environment variables are case sensitive. */
588 __gnat_get_env_vars_case_sensitive (void)
590 #if defined (WINNT) || defined (__DJGPP__)
591 return 0;
592 #else
593 return 1;
594 #endif
597 char
598 __gnat_get_default_identifier_character_set (void)
600 return '1';
603 /* Return the current working directory. */
605 void
606 __gnat_get_current_dir (char *dir, int *length)
608 #if defined (__MINGW32__)
609 TCHAR wdir[GNAT_MAX_PATH_LEN];
611 _tgetcwd (wdir, *length);
613 WS2SC (dir, wdir, GNAT_MAX_PATH_LEN);
615 #else
616 getcwd (dir, *length);
617 #endif
619 *length = strlen (dir);
621 if (dir [*length - 1] != DIR_SEPARATOR)
623 dir [*length] = DIR_SEPARATOR;
624 ++(*length);
626 dir[*length] = '\0';
629 /* Return the suffix for object files. */
631 void
632 __gnat_get_object_suffix_ptr (int *len, const char **value)
634 *value = HOST_OBJECT_SUFFIX;
636 if (*value == 0)
637 *len = 0;
638 else
639 *len = strlen (*value);
641 return;
644 /* Return the suffix for executable files. */
646 void
647 __gnat_get_executable_suffix_ptr (int *len, const char **value)
649 *value = HOST_EXECUTABLE_SUFFIX;
650 if (!*value)
651 *len = 0;
652 else
653 *len = strlen (*value);
655 return;
658 /* Return the suffix for debuggable files. Usually this is the same as the
659 executable extension. */
661 void
662 __gnat_get_debuggable_suffix_ptr (int *len, const char **value)
664 *value = HOST_EXECUTABLE_SUFFIX;
666 if (*value == 0)
667 *len = 0;
668 else
669 *len = strlen (*value);
671 return;
674 /* Returns the OS filename and corresponding encoding. */
676 void
677 __gnat_os_filename (char *filename ATTRIBUTE_UNUSED,
678 char *w_filename ATTRIBUTE_UNUSED,
679 char *os_name, int *o_length,
680 char *encoding ATTRIBUTE_UNUSED, int *e_length)
682 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
683 WS2SC (os_name, (TCHAR *)w_filename, (DWORD)*o_length);
684 *o_length = strlen (os_name);
685 strcpy (encoding, "encoding=utf8");
686 *e_length = strlen (encoding);
687 #else
688 strcpy (os_name, filename);
689 *o_length = strlen (filename);
690 *e_length = 0;
691 #endif
694 /* Delete a file. */
697 __gnat_unlink (char *path)
699 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
701 TCHAR wpath[GNAT_MAX_PATH_LEN];
703 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
704 return _tunlink (wpath);
706 #else
707 return unlink (path);
708 #endif
711 /* Rename a file. */
714 __gnat_rename (char *from, char *to)
716 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
718 TCHAR wfrom[GNAT_MAX_PATH_LEN], wto[GNAT_MAX_PATH_LEN];
720 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN);
721 S2WSC (wto, to, GNAT_MAX_PATH_LEN);
722 return _trename (wfrom, wto);
724 #else
725 return rename (from, to);
726 #endif
729 /* Changing directory. */
732 __gnat_chdir (char *path)
734 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
736 TCHAR wpath[GNAT_MAX_PATH_LEN];
738 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
739 return _tchdir (wpath);
741 #else
742 return chdir (path);
743 #endif
746 /* Removing a directory. */
749 __gnat_rmdir (char *path)
751 #if defined (__MINGW32__) && ! defined (__vxworks) && ! defined (IS_CROSS)
753 TCHAR wpath[GNAT_MAX_PATH_LEN];
755 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
756 return _trmdir (wpath);
758 #elif defined (VTHREADS)
759 /* rmdir not available */
760 return -1;
761 #else
762 return rmdir (path);
763 #endif
766 #if defined (_WIN32) || defined (__linux__) || defined (__sun__) \
767 || defined (__FreeBSD__) || defined(__DragonFly__)
768 #define HAS_TARGET_WCHAR_T
769 #endif
771 #ifdef HAS_TARGET_WCHAR_T
772 #include <wchar.h>
773 #endif
776 __gnat_fputwc(int c, FILE *stream)
778 #ifdef HAS_TARGET_WCHAR_T
779 return fputwc ((wchar_t)c, stream);
780 #else
781 return fputc (c, stream);
782 #endif
785 FILE *
786 __gnat_fopen (char *path, char *mode, int encoding ATTRIBUTE_UNUSED)
788 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
789 TCHAR wpath[GNAT_MAX_PATH_LEN];
790 TCHAR wmode[10];
792 S2WS (wmode, mode, 10);
794 if (encoding == Encoding_Unspecified)
795 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
796 else if (encoding == Encoding_UTF8)
797 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
798 else
799 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
801 return _tfopen (wpath, wmode);
803 #else
804 return GNAT_FOPEN (path, mode);
805 #endif
808 FILE *
809 __gnat_freopen (char *path,
810 char *mode,
811 FILE *stream,
812 int encoding ATTRIBUTE_UNUSED)
814 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
815 TCHAR wpath[GNAT_MAX_PATH_LEN];
816 TCHAR wmode[10];
818 S2WS (wmode, mode, 10);
820 if (encoding == Encoding_Unspecified)
821 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
822 else if (encoding == Encoding_UTF8)
823 S2WSU (wpath, path, GNAT_MAX_PATH_LEN);
824 else
825 S2WS (wpath, path, GNAT_MAX_PATH_LEN);
827 return _tfreopen (wpath, wmode, stream);
828 #else
829 return freopen (path, mode, stream);
830 #endif
834 __gnat_open_read (char *path, int fmode)
836 int fd;
837 int o_fmode = O_BINARY;
839 if (fmode)
840 o_fmode = O_TEXT;
842 #if defined (__vxworks)
843 fd = open (path, O_RDONLY | o_fmode, 0444);
844 #elif defined (__MINGW32__)
846 TCHAR wpath[GNAT_MAX_PATH_LEN];
848 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
849 fd = _topen (wpath, O_RDONLY | o_fmode, 0444);
851 #else
852 fd = GNAT_OPEN (path, O_RDONLY | o_fmode);
853 #endif
855 return fd < 0 ? -1 : fd;
858 #if defined (__MINGW32__)
859 #define PERM (S_IREAD | S_IWRITE)
860 #else
861 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
862 #endif
865 __gnat_open_rw (char *path, int fmode)
867 int fd;
868 int o_fmode = O_BINARY;
870 if (fmode)
871 o_fmode = O_TEXT;
873 #if defined (__MINGW32__)
875 TCHAR wpath[GNAT_MAX_PATH_LEN];
877 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
878 fd = _topen (wpath, O_RDWR | o_fmode, PERM);
880 #else
881 fd = GNAT_OPEN (path, O_RDWR | o_fmode, PERM);
882 #endif
884 return fd < 0 ? -1 : fd;
888 __gnat_open_create (char *path, int fmode)
890 int fd;
891 int o_fmode = O_BINARY;
893 if (fmode)
894 o_fmode = O_TEXT;
896 #if defined (__MINGW32__)
898 TCHAR wpath[GNAT_MAX_PATH_LEN];
900 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
901 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
903 #else
904 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | o_fmode, PERM);
905 #endif
907 return fd < 0 ? -1 : fd;
911 __gnat_create_output_file (char *path)
913 int fd;
914 #if defined (__MINGW32__)
916 TCHAR wpath[GNAT_MAX_PATH_LEN];
918 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
919 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
921 #else
922 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, PERM);
923 #endif
925 return fd < 0 ? -1 : fd;
929 __gnat_create_output_file_new (char *path)
931 int fd;
932 #if defined (__MINGW32__)
934 TCHAR wpath[GNAT_MAX_PATH_LEN];
936 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
937 fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
939 #else
940 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM);
941 #endif
943 return fd < 0 ? -1 : fd;
947 __gnat_open_append (char *path, int fmode)
949 int fd;
950 int o_fmode = O_BINARY;
952 if (fmode)
953 o_fmode = O_TEXT;
955 #if defined (__MINGW32__)
957 TCHAR wpath[GNAT_MAX_PATH_LEN];
959 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
960 fd = _topen (wpath, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
962 #else
963 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_APPEND | o_fmode, PERM);
964 #endif
966 return fd < 0 ? -1 : fd;
969 /* Open a new file. Return error (-1) if the file already exists. */
972 __gnat_open_new (char *path, int fmode)
974 int fd;
975 int o_fmode = O_BINARY;
977 if (fmode)
978 o_fmode = O_TEXT;
980 #if defined (__MINGW32__)
982 TCHAR wpath[GNAT_MAX_PATH_LEN];
984 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
985 fd = _topen (wpath, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
987 #else
988 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
989 #endif
991 return fd < 0 ? -1 : fd;
994 /* Open a new temp file. Return error (-1) if the file already exists. */
997 __gnat_open_new_temp (char *path, int fmode)
999 int fd;
1000 int o_fmode = O_BINARY;
1002 strcpy (path, "GNAT-XXXXXX");
1004 #if (defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
1005 || defined (__linux__) || defined (__GLIBC__) || defined (__ANDROID__) \
1006 || defined (__DragonFly__)) && !defined (__vxworks)
1007 return mkstemp (path);
1008 #elif defined (__Lynx__)
1009 mktemp (path);
1010 #else
1011 if (mktemp (path) == NULL)
1012 return -1;
1013 #endif
1015 if (fmode)
1016 o_fmode = O_TEXT;
1018 fd = GNAT_OPEN (path, O_WRONLY | O_CREAT | O_EXCL | o_fmode, PERM);
1019 return fd < 0 ? -1 : fd;
1023 __gnat_open (char *path, int fmode)
1025 int fd;
1027 #if defined (__MINGW32__)
1029 TCHAR wpath[GNAT_MAX_PATH_LEN];
1031 S2WSC (wpath, path, GNAT_MAX_PATH_LEN);
1032 fd = _topen (wpath, fmode, PERM);
1034 #else
1035 fd = GNAT_OPEN (path, fmode, PERM);
1036 #endif
1038 return fd < 0 ? -1 : fd;
1041 /****************************************************************
1042 ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information
1043 ** as possible from it, storing the result in a cache for later reuse
1044 ****************************************************************/
1046 void
1047 __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr)
1049 GNAT_STRUCT_STAT statbuf;
1050 int ret, error;
1052 if (fd != -1) {
1053 /* GNAT_FSTAT returns -1 and sets errno for failure */
1054 ret = GNAT_FSTAT (fd, &statbuf);
1055 error = ret ? errno : 0;
1057 } else {
1058 /* __gnat_stat returns errno value directly */
1059 error = __gnat_stat (name, &statbuf);
1060 ret = error ? -1 : 0;
1064 * A missing file is reported as an attr structure with error == 0 and
1065 * exists == 0.
1068 if (error == 0 || error == ENOENT)
1069 attr->error = 0;
1070 else
1071 attr->error = error;
1073 attr->regular = (!ret && S_ISREG (statbuf.st_mode));
1074 attr->directory = (!ret && S_ISDIR (statbuf.st_mode));
1076 if (!attr->regular)
1077 attr->file_length = 0;
1078 else
1079 /* st_size may be 32 bits, or 64 bits which is converted to long. We
1080 don't return a useful value for files larger than 2 gigabytes in
1081 either case. */
1082 attr->file_length = statbuf.st_size; /* all systems */
1084 attr->exists = !ret;
1086 #if !defined (_WIN32)
1087 /* on Windows requires extra system call, see __gnat_is_readable_file_attr */
1088 attr->readable = (!ret && (statbuf.st_mode & S_IRUSR));
1089 attr->writable = (!ret && (statbuf.st_mode & S_IWUSR));
1090 attr->executable = (!ret && (statbuf.st_mode & S_IXUSR));
1091 #endif
1093 if (ret != 0) {
1094 attr->timestamp = (OS_Time)-1;
1095 } else {
1096 attr->timestamp = (OS_Time)statbuf.st_mtime;
1100 /****************************************************************
1101 ** Return the number of bytes in the specified file
1102 ****************************************************************/
1104 __int64
1105 __gnat_file_length_attr (int fd, char* name, struct file_attributes* attr)
1107 if (attr->file_length == -1) {
1108 __gnat_stat_to_attr (fd, name, attr);
1111 return attr->file_length;
1114 __int64
1115 __gnat_file_length (int fd)
1117 struct file_attributes attr;
1118 __gnat_reset_attributes (&attr);
1119 return __gnat_file_length_attr (fd, NULL, &attr);
1122 long
1123 __gnat_file_length_long (int fd)
1125 struct file_attributes attr;
1126 __gnat_reset_attributes (&attr);
1127 return (long)__gnat_file_length_attr (fd, NULL, &attr);
1130 __int64
1131 __gnat_named_file_length (char *name)
1133 struct file_attributes attr;
1134 __gnat_reset_attributes (&attr);
1135 return __gnat_file_length_attr (-1, name, &attr);
1138 /* Create a temporary filename and put it in string pointed to by
1139 TMP_FILENAME. */
1141 void
1142 __gnat_tmp_name (char *tmp_filename)
1144 #if defined (__MINGW32__)
1146 char *pname;
1147 char prefix[25];
1149 /* tempnam tries to create a temporary file in directory pointed to by
1150 TMP environment variable, in c:\temp if TMP is not set, and in
1151 directory specified by P_tmpdir in stdio.h if c:\temp does not
1152 exist. The filename will be created with the prefix "gnat-". */
1154 sprintf (prefix, "gnat-%d-", (int)getpid());
1155 pname = (char *) _tempnam ("c:\\temp", prefix);
1157 /* if pname is NULL, the file was not created properly, the disk is full
1158 or there is no more free temporary files */
1160 if (pname == NULL)
1161 *tmp_filename = '\0';
1163 /* If pname start with a back slash and not path information it means that
1164 the filename is valid for the current working directory. */
1166 else if (pname[0] == '\\')
1168 strcpy (tmp_filename, ".\\");
1169 strcat (tmp_filename, pname+1);
1171 else
1172 strcpy (tmp_filename, pname);
1174 free (pname);
1177 #elif defined (__linux__) || defined (__FreeBSD__) || defined (__NetBSD__) \
1178 || defined (__OpenBSD__) || defined (__GLIBC__) || defined (__ANDROID__) \
1179 || defined (__DragonFly__)
1180 #define MAX_SAFE_PATH 1000
1181 char *tmpdir = getenv ("TMPDIR");
1183 /* If tmpdir is longer than MAX_SAFE_PATH, revert to default value to avoid
1184 a buffer overflow. */
1185 if (tmpdir == NULL || strlen (tmpdir) > MAX_SAFE_PATH)
1186 #ifdef __ANDROID__
1187 strcpy (tmp_filename, "/cache/gnat-XXXXXX");
1188 #else
1189 strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
1190 #endif
1191 else
1192 sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
1194 close (mkstemp(tmp_filename));
1195 #elif defined (__vxworks) && !defined (VTHREADS)
1196 int index;
1197 char *pos;
1198 char *savepos;
1199 static ushort_t seed = 0; /* used to generate unique name */
1201 /* Generate a unique name. */
1202 strcpy (tmp_filename, "tmp");
1204 index = 5;
1205 savepos = pos = tmp_filename + strlen (tmp_filename) + index;
1206 *pos = '\0';
1208 while (1)
1210 FILE *f;
1211 ushort_t t;
1213 /* Fill up the name buffer from the last position. */
1214 seed++;
1215 for (t = seed; 0 <= --index; t >>= 3)
1216 *--pos = '0' + (t & 07);
1218 /* Check to see if its unique, if not bump the seed and try again. */
1219 f = fopen (tmp_filename, "r");
1220 if (f == NULL)
1221 break;
1222 fclose (f);
1223 pos = savepos;
1224 index = 5;
1226 #else
1227 tmpnam (tmp_filename);
1228 #endif
1231 /* Open directory and returns a DIR pointer. */
1233 DIR* __gnat_opendir (char *name)
1235 #if defined (__MINGW32__)
1236 TCHAR wname[GNAT_MAX_PATH_LEN];
1238 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1239 return (DIR*)_topendir (wname);
1241 #else
1242 return opendir (name);
1243 #endif
1246 /* Read the next entry in a directory. The returned string points somewhere
1247 in the buffer. */
1249 #if defined (__sun__)
1250 /* For Solaris, be sure to use the 64-bit version, otherwise NFS reads may
1251 fail with EOVERFLOW if the server uses 64-bit cookies. */
1252 #define dirent dirent64
1253 #define readdir readdir64
1254 #endif
1256 char *
1257 __gnat_readdir (DIR *dirp, char *buffer, int *len)
1259 #if defined (__MINGW32__)
1260 struct _tdirent *dirent = _treaddir ((_TDIR*)dirp);
1262 if (dirent != NULL)
1264 WS2SC (buffer, dirent->d_name, GNAT_MAX_PATH_LEN);
1265 *len = strlen (buffer);
1267 return buffer;
1269 else
1270 return NULL;
1272 #elif defined (HAVE_READDIR_R)
1273 /* If possible, try to use the thread-safe version. */
1274 if (readdir_r (dirp, buffer) != NULL)
1276 *len = strlen (((struct dirent*) buffer)->d_name);
1277 return ((struct dirent*) buffer)->d_name;
1279 else
1280 return NULL;
1282 #else
1283 struct dirent *dirent = (struct dirent *) readdir (dirp);
1285 if (dirent != NULL)
1287 strcpy (buffer, dirent->d_name);
1288 *len = strlen (buffer);
1289 return buffer;
1291 else
1292 return NULL;
1294 #endif
1297 /* Close a directory entry. */
1299 int __gnat_closedir (DIR *dirp)
1301 #if defined (__MINGW32__)
1302 return _tclosedir ((_TDIR*)dirp);
1304 #else
1305 return closedir (dirp);
1306 #endif
1309 /* Returns 1 if readdir is thread safe, 0 otherwise. */
1312 __gnat_readdir_is_thread_safe (void)
1314 #ifdef HAVE_READDIR_R
1315 return 1;
1316 #else
1317 return 0;
1318 #endif
1321 #if defined (_WIN32)
1322 /* Number of seconds between <Jan 1st 1601> and <Jan 1st 1970>. */
1323 static const unsigned long long w32_epoch_offset = 11644473600ULL;
1325 /* Returns the file modification timestamp using Win32 routines which are
1326 immune against daylight saving time change. It is in fact not possible to
1327 use fstat for this purpose as the DST modify the st_mtime field of the
1328 stat structure. */
1330 static time_t
1331 win32_filetime (HANDLE h)
1333 union
1335 FILETIME ft_time;
1336 unsigned long long ull_time;
1337 } t_write;
1339 /* GetFileTime returns FILETIME data which are the number of 100 nanosecs
1340 since <Jan 1st 1601>. This function must return the number of seconds
1341 since <Jan 1st 1970>. */
1343 if (GetFileTime (h, NULL, NULL, &t_write.ft_time))
1344 return (time_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1345 return (time_t) 0;
1348 /* As above but starting from a FILETIME. */
1349 static void
1350 f2t (const FILETIME *ft, __time64_t *t)
1352 union
1354 FILETIME ft_time;
1355 unsigned long long ull_time;
1356 } t_write;
1358 t_write.ft_time = *ft;
1359 *t = (__time64_t) (t_write.ull_time / 10000000ULL - w32_epoch_offset);
1361 #endif
1363 /* Return a GNAT time stamp given a file name. */
1365 OS_Time
1366 __gnat_file_time_name_attr (char* name, struct file_attributes* attr)
1368 if (attr->timestamp == (OS_Time)-2) {
1369 #if defined (_WIN32)
1370 BOOL res;
1371 WIN32_FILE_ATTRIBUTE_DATA fad;
1372 __time64_t ret = -1;
1373 TCHAR wname[GNAT_MAX_PATH_LEN];
1374 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1376 if ((res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad)))
1377 f2t (&fad.ftLastWriteTime, &ret);
1378 attr->timestamp = (OS_Time) ret;
1379 #else
1380 __gnat_stat_to_attr (-1, name, attr);
1381 #endif
1383 return attr->timestamp;
1386 OS_Time
1387 __gnat_file_time_name (char *name)
1389 struct file_attributes attr;
1390 __gnat_reset_attributes (&attr);
1391 return __gnat_file_time_name_attr (name, &attr);
1394 /* Return a GNAT time stamp given a file descriptor. */
1396 OS_Time
1397 __gnat_file_time_fd_attr (int fd, struct file_attributes* attr)
1399 if (attr->timestamp == (OS_Time)-2) {
1400 #if defined (_WIN32)
1401 HANDLE h = (HANDLE) _get_osfhandle (fd);
1402 time_t ret = win32_filetime (h);
1403 attr->timestamp = (OS_Time) ret;
1405 #else
1406 __gnat_stat_to_attr (fd, NULL, attr);
1407 #endif
1410 return attr->timestamp;
1413 OS_Time
1414 __gnat_file_time_fd (int fd)
1416 struct file_attributes attr;
1417 __gnat_reset_attributes (&attr);
1418 return __gnat_file_time_fd_attr (fd, &attr);
1421 /* Set the file time stamp. */
1423 void
1424 __gnat_set_file_time_name (char *name, time_t time_stamp)
1426 #if defined (__vxworks)
1428 /* Code to implement __gnat_set_file_time_name for these systems. */
1430 #elif defined (_WIN32)
1431 union
1433 FILETIME ft_time;
1434 unsigned long long ull_time;
1435 } t_write;
1436 TCHAR wname[GNAT_MAX_PATH_LEN];
1438 S2WSC (wname, name, GNAT_MAX_PATH_LEN);
1440 HANDLE h = CreateFile
1441 (wname, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
1442 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
1443 NULL);
1444 if (h == INVALID_HANDLE_VALUE)
1445 return;
1446 /* Add number of seconds between <Jan 1st 1601> and <Jan 1st 1970> */
1447 t_write.ull_time = ((unsigned long long)time_stamp + w32_epoch_offset);
1448 /* Convert to 100 nanosecond units */
1449 t_write.ull_time *= 10000000ULL;
1451 SetFileTime(h, NULL, NULL, &t_write.ft_time);
1452 CloseHandle (h);
1453 return;
1455 #else
1456 struct utimbuf utimbuf;
1457 time_t t;
1459 /* Set modification time to requested time. */
1460 utimbuf.modtime = time_stamp;
1462 /* Set access time to now in local time. */
1463 t = time ((time_t) 0);
1464 utimbuf.actime = mktime (localtime (&t));
1466 utime (name, &utimbuf);
1467 #endif
1470 /* Get the list of installed standard libraries from the
1471 HKEY_LOCAL_MACHINE\SOFTWARE\Ada Core Technologies\GNAT\Standard Libraries
1472 key. */
1474 char *
1475 __gnat_get_libraries_from_registry (void)
1477 char *result = (char *) xmalloc (1);
1479 result[0] = '\0';
1481 #if defined (_WIN32) && ! defined (__vxworks) && ! defined (IS_CROSS)
1483 HKEY reg_key;
1484 DWORD name_size, value_size;
1485 char name[256];
1486 char value[256];
1487 DWORD type;
1488 DWORD index;
1489 LONG res;
1491 /* First open the key. */
1492 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0, KEY_READ, &reg_key);
1494 if (res == ERROR_SUCCESS)
1495 res = RegOpenKeyExA (reg_key, "Ada Core Technologies", 0,
1496 KEY_READ, &reg_key);
1498 if (res == ERROR_SUCCESS)
1499 res = RegOpenKeyExA (reg_key, "GNAT", 0, KEY_READ, &reg_key);
1501 if (res == ERROR_SUCCESS)
1502 res = RegOpenKeyExA (reg_key, "Standard Libraries", 0, KEY_READ, &reg_key);
1504 /* If the key exists, read out all the values in it and concatenate them
1505 into a path. */
1506 for (index = 0; res == ERROR_SUCCESS; index++)
1508 value_size = name_size = 256;
1509 res = RegEnumValueA (reg_key, index, name, &name_size, 0,
1510 &type, (LPBYTE)value, &value_size);
1512 if (res == ERROR_SUCCESS && type == REG_SZ)
1514 char *old_result = result;
1516 result = (char *) xmalloc (strlen (old_result) + value_size + 2);
1517 strcpy (result, old_result);
1518 strcat (result, value);
1519 strcat (result, ";");
1520 free (old_result);
1524 /* Remove the trailing ";". */
1525 if (result[0] != 0)
1526 result[strlen (result) - 1] = 0;
1528 #endif
1529 return result;
1532 /* Query information for the given file NAME and return it in STATBUF.
1533 * Returns 0 for success, or errno value for failure.
1536 __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf)
1538 #ifdef __MINGW32__
1539 WIN32_FILE_ATTRIBUTE_DATA fad;
1540 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1541 int name_len;
1542 BOOL res;
1543 DWORD error;
1545 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1546 name_len = _tcslen (wname);
1548 if (name_len > GNAT_MAX_PATH_LEN)
1549 return EINVAL;
1551 ZeroMemory (statbuf, sizeof(GNAT_STRUCT_STAT));
1553 res = GetFileAttributesEx (wname, GetFileExInfoStandard, &fad);
1555 if (res == FALSE) {
1556 error = GetLastError();
1558 /* Check file existence using GetFileAttributes() which does not fail on
1559 special Windows files like con:, aux:, nul: etc... */
1561 if (GetFileAttributes(wname) != INVALID_FILE_ATTRIBUTES) {
1562 /* Just pretend that it is a regular and readable file */
1563 statbuf->st_mode = S_IFREG | S_IREAD | S_IWRITE;
1564 return 0;
1567 switch (error) {
1568 case ERROR_ACCESS_DENIED:
1569 case ERROR_SHARING_VIOLATION:
1570 case ERROR_LOCK_VIOLATION:
1571 case ERROR_SHARING_BUFFER_EXCEEDED:
1572 return EACCES;
1573 case ERROR_BUFFER_OVERFLOW:
1574 return ENAMETOOLONG;
1575 case ERROR_NOT_ENOUGH_MEMORY:
1576 return ENOMEM;
1577 default:
1578 return ENOENT;
1582 f2t (&fad.ftCreationTime, &statbuf->st_ctime);
1583 f2t (&fad.ftLastWriteTime, &statbuf->st_mtime);
1584 f2t (&fad.ftLastAccessTime, &statbuf->st_atime);
1586 statbuf->st_size =
1587 (__int64)fad.nFileSizeLow | (__int64)fad.nFileSizeHigh << 32;
1589 /* We do not have the S_IEXEC attribute, but this is not used on GNAT. */
1590 statbuf->st_mode = S_IREAD;
1592 if (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1593 statbuf->st_mode |= S_IFDIR;
1594 else
1595 statbuf->st_mode |= S_IFREG;
1597 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1598 statbuf->st_mode |= S_IWRITE;
1600 return 0;
1602 #else
1603 return GNAT_STAT (name, statbuf) == 0 ? 0 : errno;
1604 #endif
1607 /*************************************************************************
1608 ** Check whether a file exists
1609 *************************************************************************/
1612 __gnat_file_exists_attr (char* name, struct file_attributes* attr)
1614 if (attr->exists == ATTR_UNSET)
1615 __gnat_stat_to_attr (-1, name, attr);
1617 return attr->exists;
1621 __gnat_file_exists (char *name)
1623 struct file_attributes attr;
1624 __gnat_reset_attributes (&attr);
1625 return __gnat_file_exists_attr (name, &attr);
1628 /**********************************************************************
1629 ** Whether name is an absolute path
1630 **********************************************************************/
1633 __gnat_is_absolute_path (char *name, int length)
1635 #ifdef __vxworks
1636 /* On VxWorks systems, an absolute path can be represented (depending on
1637 the host platform) as either /dir/file, or device:/dir/file, or
1638 device:drive_letter:/dir/file. */
1640 int index;
1642 if (name[0] == '/')
1643 return 1;
1645 for (index = 0; index < length; index++)
1647 if (name[index] == ':' &&
1648 ((name[index + 1] == '/') ||
1649 (isalpha (name[index + 1]) && index + 2 <= length &&
1650 name[index + 2] == '/')))
1651 return 1;
1653 else if (name[index] == '/')
1654 return 0;
1656 return 0;
1657 #else
1658 return (length != 0) &&
1659 (*name == '/' || *name == DIR_SEPARATOR
1660 #if defined (WINNT) || defined(__DJGPP__)
1661 || (length > 1 && ISALPHA (name[0]) && name[1] == ':')
1662 #endif
1664 #endif
1668 __gnat_is_regular_file_attr (char* name, struct file_attributes* attr)
1670 if (attr->regular == ATTR_UNSET)
1671 __gnat_stat_to_attr (-1, name, attr);
1673 return attr->regular;
1677 __gnat_is_regular_file (char *name)
1679 struct file_attributes attr;
1681 __gnat_reset_attributes (&attr);
1682 return __gnat_is_regular_file_attr (name, &attr);
1686 __gnat_is_regular_file_fd (int fd)
1688 int ret;
1689 GNAT_STRUCT_STAT statbuf;
1691 ret = GNAT_FSTAT (fd, &statbuf);
1692 return (!ret && S_ISREG (statbuf.st_mode));
1696 __gnat_is_directory_attr (char* name, struct file_attributes* attr)
1698 if (attr->directory == ATTR_UNSET)
1699 __gnat_stat_to_attr (-1, name, attr);
1701 return attr->directory;
1705 __gnat_is_directory (char *name)
1707 struct file_attributes attr;
1709 __gnat_reset_attributes (&attr);
1710 return __gnat_is_directory_attr (name, &attr);
1713 #if defined (_WIN32)
1715 /* Returns the same constant as GetDriveType but takes a pathname as
1716 argument. */
1718 static UINT
1719 GetDriveTypeFromPath (TCHAR *wfullpath)
1721 TCHAR wdrv[MAX_PATH];
1722 TCHAR wpath[MAX_PATH];
1723 TCHAR wfilename[MAX_PATH];
1724 TCHAR wext[MAX_PATH];
1726 _tsplitpath (wfullpath, wdrv, wpath, wfilename, wext);
1728 if (_tcslen (wdrv) != 0)
1730 /* we have a drive specified. */
1731 _tcscat (wdrv, _T("\\"));
1732 return GetDriveType (wdrv);
1734 else
1736 /* No drive specified. */
1738 /* Is this a relative path, if so get current drive type. */
1739 if (wpath[0] != _T('\\') ||
1740 (_tcslen (wpath) > 2 && wpath[0] == _T('\\')
1741 && wpath[1] != _T('\\')))
1742 return GetDriveType (NULL);
1744 UINT result = GetDriveType (wpath);
1746 /* Cannot guess the drive type, is this \\.\ ? */
1748 if (result == DRIVE_NO_ROOT_DIR &&
1749 _tcslen (wpath) >= 4 && wpath[0] == _T('\\') && wpath[1] == _T('\\')
1750 && wpath[2] == _T('.') && wpath[3] == _T('\\'))
1752 if (_tcslen (wpath) == 4)
1753 _tcscat (wpath, wfilename);
1755 LPTSTR p = &wpath[4];
1756 LPTSTR b = _tcschr (p, _T('\\'));
1758 if (b != NULL)
1760 /* logical drive \\.\c\dir\file */
1761 *b++ = _T(':');
1762 *b++ = _T('\\');
1763 *b = _T('\0');
1765 else
1766 _tcscat (p, _T(":\\"));
1768 return GetDriveType (p);
1771 return result;
1775 /* This MingW section contains code to work with ACL. */
1776 static int
1777 __gnat_check_OWNER_ACL (TCHAR *wname,
1778 DWORD CheckAccessDesired,
1779 GENERIC_MAPPING CheckGenericMapping)
1781 DWORD dwAccessDesired, dwAccessAllowed;
1782 PRIVILEGE_SET PrivilegeSet;
1783 DWORD dwPrivSetSize = sizeof (PRIVILEGE_SET);
1784 BOOL fAccessGranted = FALSE;
1785 HANDLE hToken = NULL;
1786 DWORD nLength = 0;
1787 PSECURITY_DESCRIPTOR pSD = NULL;
1789 GetFileSecurity
1790 (wname, OWNER_SECURITY_INFORMATION |
1791 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1792 NULL, 0, &nLength);
1794 if ((pSD = (SECURITY_DESCRIPTOR *) HeapAlloc
1795 (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength)) == NULL)
1796 return 0;
1798 /* Obtain the security descriptor. */
1800 if (!GetFileSecurity
1801 (wname, OWNER_SECURITY_INFORMATION |
1802 GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
1803 pSD, nLength, &nLength))
1804 goto error;
1806 if (!ImpersonateSelf (SecurityImpersonation))
1807 goto error;
1809 if (!OpenThreadToken
1810 (GetCurrentThread(), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken))
1811 goto error;
1813 /* Undoes the effect of ImpersonateSelf. */
1815 RevertToSelf ();
1817 /* We want to test for write permissions. */
1819 dwAccessDesired = CheckAccessDesired;
1821 MapGenericMask (&dwAccessDesired, &CheckGenericMapping);
1823 if (!AccessCheck
1824 (pSD , /* security descriptor to check */
1825 hToken, /* impersonation token */
1826 dwAccessDesired, /* requested access rights */
1827 &CheckGenericMapping, /* pointer to GENERIC_MAPPING */
1828 &PrivilegeSet, /* receives privileges used in check */
1829 &dwPrivSetSize, /* size of PrivilegeSet buffer */
1830 &dwAccessAllowed, /* receives mask of allowed access rights */
1831 &fAccessGranted))
1832 goto error;
1834 CloseHandle (hToken);
1835 HeapFree (GetProcessHeap (), 0, pSD);
1836 return fAccessGranted;
1838 error:
1839 if (hToken)
1840 CloseHandle (hToken);
1841 HeapFree (GetProcessHeap (), 0, pSD);
1842 return 0;
1845 static void
1846 __gnat_set_OWNER_ACL (TCHAR *wname,
1847 ACCESS_MODE AccessMode,
1848 DWORD AccessPermissions)
1850 PACL pOldDACL = NULL;
1851 PACL pNewDACL = NULL;
1852 PSECURITY_DESCRIPTOR pSD = NULL;
1853 EXPLICIT_ACCESS ea;
1854 TCHAR username [100];
1855 DWORD unsize = 100;
1857 /* Get current user, he will act as the owner */
1859 if (!GetUserName (username, &unsize))
1860 return;
1862 if (GetNamedSecurityInfo
1863 (wname,
1864 SE_FILE_OBJECT,
1865 DACL_SECURITY_INFORMATION,
1866 NULL, NULL, &pOldDACL, NULL, &pSD) != ERROR_SUCCESS)
1867 return;
1869 BuildExplicitAccessWithName
1870 (&ea, username, AccessPermissions, (ACCESS_MODE) AccessMode, NO_INHERITANCE);
1872 if (AccessMode == SET_ACCESS)
1874 /* SET_ACCESS, we want to set an explicte set of permissions, do not
1875 merge with current DACL. */
1876 if (SetEntriesInAcl (1, &ea, NULL, &pNewDACL) != ERROR_SUCCESS)
1877 return;
1879 else
1880 if (SetEntriesInAcl (1, &ea, pOldDACL, &pNewDACL) != ERROR_SUCCESS)
1881 return;
1883 if (SetNamedSecurityInfo
1884 (wname, SE_FILE_OBJECT,
1885 DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL) != ERROR_SUCCESS)
1886 return;
1888 LocalFree (pSD);
1889 LocalFree (pNewDACL);
1892 /* Check if it is possible to use ACL for wname, the file must not be on a
1893 network drive. */
1895 static int
1896 __gnat_can_use_acl (TCHAR *wname)
1898 return __gnat_use_acl && GetDriveTypeFromPath (wname) != DRIVE_REMOTE;
1901 #endif /* defined (_WIN32) */
1904 __gnat_is_readable_file_attr (char* name, struct file_attributes* attr)
1906 if (attr->readable == ATTR_UNSET)
1908 #if defined (_WIN32)
1909 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1910 GENERIC_MAPPING GenericMapping;
1912 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1914 if (__gnat_can_use_acl (wname))
1916 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1917 GenericMapping.GenericRead = GENERIC_READ;
1918 attr->readable =
1919 __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping);
1921 else
1922 attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES;
1923 #else
1924 __gnat_stat_to_attr (-1, name, attr);
1925 #endif
1928 return attr->readable;
1932 __gnat_is_read_accessible_file (char *name)
1934 #if defined (_WIN32)
1935 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1937 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1939 return !_waccess (wname, 4);
1941 #elif defined (__vxworks)
1942 int fd;
1944 if ((fd = open (name, O_RDONLY, 0)) < 0)
1945 return 0;
1946 close (fd);
1947 return 1;
1949 #else
1950 return !access (name, R_OK);
1951 #endif
1955 __gnat_is_readable_file (char *name)
1957 struct file_attributes attr;
1959 __gnat_reset_attributes (&attr);
1960 return __gnat_is_readable_file_attr (name, &attr);
1964 __gnat_is_writable_file_attr (char* name, struct file_attributes* attr)
1966 if (attr->writable == ATTR_UNSET)
1968 #if defined (_WIN32)
1969 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
1970 GENERIC_MAPPING GenericMapping;
1972 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
1974 if (__gnat_can_use_acl (wname))
1976 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
1977 GenericMapping.GenericWrite = GENERIC_WRITE;
1979 attr->writable = __gnat_check_OWNER_ACL
1980 (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping)
1981 && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1983 else
1984 attr->writable =
1985 !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY);
1987 #else
1988 __gnat_stat_to_attr (-1, name, attr);
1989 #endif
1992 return attr->writable;
1996 __gnat_is_writable_file (char *name)
1998 struct file_attributes attr;
2000 __gnat_reset_attributes (&attr);
2001 return __gnat_is_writable_file_attr (name, &attr);
2005 __gnat_is_write_accessible_file (char *name)
2007 #if defined (_WIN32)
2008 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2010 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2012 return !_waccess (wname, 2);
2014 #elif defined (__vxworks)
2015 int fd;
2017 if ((fd = open (name, O_WRONLY, 0)) < 0)
2018 return 0;
2019 close (fd);
2020 return 1;
2022 #else
2023 return !access (name, W_OK);
2024 #endif
2028 __gnat_is_executable_file_attr (char* name, struct file_attributes* attr)
2030 if (attr->executable == ATTR_UNSET)
2032 #if defined (_WIN32)
2033 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2034 GENERIC_MAPPING GenericMapping;
2036 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2038 if (__gnat_can_use_acl (wname))
2040 ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING));
2041 GenericMapping.GenericExecute = GENERIC_EXECUTE;
2043 attr->executable =
2044 __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping);
2046 else
2048 TCHAR *l, *last = _tcsstr(wname, _T(".exe"));
2050 /* look for last .exe */
2051 if (last)
2052 while ((l = _tcsstr(last+1, _T(".exe"))))
2053 last = l;
2055 attr->executable =
2056 GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES
2057 && (last - wname) == (int) (_tcslen (wname) - 4);
2059 #else
2060 __gnat_stat_to_attr (-1, name, attr);
2061 #endif
2064 return attr->regular && attr->executable;
2068 __gnat_is_executable_file (char *name)
2070 struct file_attributes attr;
2072 __gnat_reset_attributes (&attr);
2073 return __gnat_is_executable_file_attr (name, &attr);
2076 void
2077 __gnat_set_writable (char *name)
2079 #if defined (_WIN32)
2080 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2082 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2084 if (__gnat_can_use_acl (wname))
2085 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_WRITE);
2087 SetFileAttributes
2088 (wname, GetFileAttributes (wname) & ~FILE_ATTRIBUTE_READONLY);
2089 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2090 GNAT_STRUCT_STAT statbuf;
2092 if (GNAT_STAT (name, &statbuf) == 0)
2094 statbuf.st_mode = statbuf.st_mode | S_IWUSR;
2095 chmod (name, statbuf.st_mode);
2097 #endif
2100 /* must match definition in s-os_lib.ads */
2101 #define S_OWNER 1
2102 #define S_GROUP 2
2103 #define S_OTHERS 4
2105 void
2106 __gnat_set_executable (char *name, int mode ATTRIBUTE_UNUSED)
2108 #if defined (_WIN32)
2109 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2111 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2113 if (__gnat_can_use_acl (wname))
2114 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_EXECUTE);
2116 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2117 GNAT_STRUCT_STAT statbuf;
2119 if (GNAT_STAT (name, &statbuf) == 0)
2121 if (mode & S_OWNER)
2122 statbuf.st_mode = statbuf.st_mode | S_IXUSR;
2123 if (mode & S_GROUP)
2124 statbuf.st_mode = statbuf.st_mode | S_IXGRP;
2125 if (mode & S_OTHERS)
2126 statbuf.st_mode = statbuf.st_mode | S_IXOTH;
2127 chmod (name, statbuf.st_mode);
2129 #endif
2132 void
2133 __gnat_set_non_writable (char *name)
2135 #if defined (_WIN32)
2136 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2138 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2140 if (__gnat_can_use_acl (wname))
2141 __gnat_set_OWNER_ACL
2142 (wname, DENY_ACCESS,
2143 FILE_WRITE_DATA | FILE_APPEND_DATA |
2144 FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES);
2146 SetFileAttributes
2147 (wname, GetFileAttributes (wname) | FILE_ATTRIBUTE_READONLY);
2148 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2149 GNAT_STRUCT_STAT statbuf;
2151 if (GNAT_STAT (name, &statbuf) == 0)
2153 statbuf.st_mode = statbuf.st_mode & 07577;
2154 chmod (name, statbuf.st_mode);
2156 #endif
2159 void
2160 __gnat_set_readable (char *name)
2162 #if defined (_WIN32)
2163 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2165 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2167 if (__gnat_can_use_acl (wname))
2168 __gnat_set_OWNER_ACL (wname, GRANT_ACCESS, FILE_GENERIC_READ);
2170 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2171 GNAT_STRUCT_STAT statbuf;
2173 if (GNAT_STAT (name, &statbuf) == 0)
2175 chmod (name, statbuf.st_mode | S_IREAD);
2177 #endif
2180 void
2181 __gnat_set_non_readable (char *name)
2183 #if defined (_WIN32)
2184 TCHAR wname [GNAT_MAX_PATH_LEN + 2];
2186 S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2);
2188 if (__gnat_can_use_acl (wname))
2189 __gnat_set_OWNER_ACL (wname, DENY_ACCESS, FILE_GENERIC_READ);
2191 #elif ! (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
2192 GNAT_STRUCT_STAT statbuf;
2194 if (GNAT_STAT (name, &statbuf) == 0)
2196 chmod (name, statbuf.st_mode & (~S_IREAD));
2198 #endif
2202 __gnat_is_symbolic_link_attr (char* name ATTRIBUTE_UNUSED,
2203 struct file_attributes* attr)
2205 if (attr->symbolic_link == ATTR_UNSET)
2207 #if defined (__vxworks)
2208 attr->symbolic_link = 0;
2210 #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__)
2211 int ret;
2212 GNAT_STRUCT_STAT statbuf;
2213 ret = GNAT_LSTAT (name, &statbuf);
2214 attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode));
2215 #else
2216 attr->symbolic_link = 0;
2217 #endif
2219 return attr->symbolic_link;
2223 __gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED)
2225 struct file_attributes attr;
2227 __gnat_reset_attributes (&attr);
2228 return __gnat_is_symbolic_link_attr (name, &attr);
2231 #if defined (__sun__)
2232 /* Using fork on Solaris will duplicate all the threads. fork1, which
2233 duplicates only the active thread, must be used instead, or spawning
2234 subprocess from a program with tasking will lead into numerous problems. */
2235 #define fork fork1
2236 #endif
2239 __gnat_portable_spawn (char *args[] ATTRIBUTE_UNUSED)
2241 int status ATTRIBUTE_UNUSED = 0;
2242 int finished ATTRIBUTE_UNUSED;
2243 int pid ATTRIBUTE_UNUSED;
2245 #if defined (__vxworks) || defined(__PikeOS__)
2246 return -1;
2248 #elif defined (__DJGPP__) || defined (_WIN32)
2249 /* args[0] must be quotes as it could contain a full pathname with spaces */
2250 char *args_0 = args[0];
2251 args[0] = (char *)xmalloc (strlen (args_0) + 3);
2252 strcpy (args[0], "\"");
2253 strcat (args[0], args_0);
2254 strcat (args[0], "\"");
2256 status = spawnvp (P_WAIT, args_0, (char ** const)args);
2258 /* restore previous value */
2259 free (args[0]);
2260 args[0] = (char *)args_0;
2262 if (status < 0)
2263 return -1;
2264 else
2265 return status;
2267 #else
2269 pid = fork ();
2270 if (pid < 0)
2271 return -1;
2273 if (pid == 0)
2275 /* The child. */
2276 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2277 _exit (1);
2280 /* The parent. */
2281 finished = waitpid (pid, &status, 0);
2283 if (finished != pid || WIFEXITED (status) == 0)
2284 return -1;
2286 return WEXITSTATUS (status);
2287 #endif
2289 return 0;
2292 /* Create a copy of the given file descriptor.
2293 Return -1 if an error occurred. */
2296 __gnat_dup (int oldfd)
2298 #if defined (__vxworks) && !defined (__RTP__)
2299 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2300 RTPs. */
2301 return -1;
2302 #else
2303 return dup (oldfd);
2304 #endif
2307 /* Make newfd be the copy of oldfd, closing newfd first if necessary.
2308 Return -1 if an error occurred. */
2311 __gnat_dup2 (int oldfd ATTRIBUTE_UNUSED, int newfd ATTRIBUTE_UNUSED)
2313 #if defined (__vxworks) && !defined (__RTP__)
2314 /* Not supported on VxWorks 5.x, but supported on VxWorks 6.0 when using
2315 RTPs. */
2316 return -1;
2317 #elif defined (__PikeOS__)
2318 /* Not supported. */
2319 return -1;
2320 #elif defined (_WIN32)
2321 /* Special case when oldfd and newfd are identical and are the standard
2322 input, output or error as this makes Windows XP hangs. Note that we
2323 do that only for standard file descriptors that are known to be valid. */
2324 if (oldfd == newfd && newfd >= 0 && newfd <= 2)
2325 return newfd;
2326 else
2327 return dup2 (oldfd, newfd);
2328 #else
2329 return dup2 (oldfd, newfd);
2330 #endif
2334 __gnat_number_of_cpus (void)
2336 int cores = 1;
2338 #if defined (__linux__) || defined (__sun__) || defined (_AIX) \
2339 || defined (__APPLE__) || defined (__FreeBSD__) || defined (__OpenBSD__) \
2340 || defined (__DragonFly__) || defined (__NetBSD__)
2341 cores = (int) sysconf (_SC_NPROCESSORS_ONLN);
2343 #elif defined (__hpux__)
2344 struct pst_dynamic psd;
2345 if (pstat_getdynamic (&psd, sizeof (psd), 1, 0) != -1)
2346 cores = (int) psd.psd_proc_cnt;
2348 #elif defined (_WIN32)
2349 SYSTEM_INFO sysinfo;
2350 GetSystemInfo (&sysinfo);
2351 cores = (int) sysinfo.dwNumberOfProcessors;
2353 #elif defined (_WRS_CONFIG_SMP)
2354 unsigned int vxCpuConfiguredGet (void);
2356 cores = vxCpuConfiguredGet ();
2358 #endif
2360 return cores;
2363 /* WIN32 code to implement a wait call that wait for any child process. */
2365 #if defined (_WIN32)
2367 /* Synchronization code, to be thread safe. */
2369 #ifdef CERT
2371 /* For the Cert run times on native Windows we use dummy functions
2372 for locking and unlocking tasks since we do not support multiple
2373 threads on this configuration (Cert run time on native Windows). */
2375 static void EnterCS (void) {}
2376 static void LeaveCS (void) {}
2377 static void SignalListChanged (void) {}
2379 #else
2381 CRITICAL_SECTION ProcListCS;
2382 HANDLE ProcListEvt = NULL;
2384 static void EnterCS (void)
2386 EnterCriticalSection(&ProcListCS);
2389 static void LeaveCS (void)
2391 LeaveCriticalSection(&ProcListCS);
2394 static void SignalListChanged (void)
2396 SetEvent (ProcListEvt);
2399 #endif
2401 static HANDLE *HANDLES_LIST = NULL;
2402 static int *PID_LIST = NULL, plist_length = 0, plist_max_length = 0;
2404 static void
2405 add_handle (HANDLE h, int pid)
2407 /* -------------------- critical section -------------------- */
2408 EnterCS();
2410 if (plist_length == plist_max_length)
2412 plist_max_length += 100;
2413 HANDLES_LIST =
2414 (HANDLE *) xrealloc (HANDLES_LIST, sizeof (HANDLE) * plist_max_length);
2415 PID_LIST =
2416 (int *) xrealloc (PID_LIST, sizeof (int) * plist_max_length);
2419 HANDLES_LIST[plist_length] = h;
2420 PID_LIST[plist_length] = pid;
2421 ++plist_length;
2423 SignalListChanged();
2424 LeaveCS();
2425 /* -------------------- critical section -------------------- */
2429 __gnat_win32_remove_handle (HANDLE h, int pid)
2431 int j;
2432 int found = 0;
2434 /* -------------------- critical section -------------------- */
2435 EnterCS();
2437 for (j = 0; j < plist_length; j++)
2439 if ((HANDLES_LIST[j] == h) || (PID_LIST[j] == pid))
2441 CloseHandle (h);
2442 --plist_length;
2443 HANDLES_LIST[j] = HANDLES_LIST[plist_length];
2444 PID_LIST[j] = PID_LIST[plist_length];
2445 found = 1;
2446 break;
2450 LeaveCS();
2451 /* -------------------- critical section -------------------- */
2453 if (found)
2454 SignalListChanged();
2456 return found;
2459 static void
2460 win32_no_block_spawn (char *command, char *args[], HANDLE *h, int *pid)
2462 BOOL result;
2463 STARTUPINFO SI;
2464 PROCESS_INFORMATION PI;
2465 SECURITY_ATTRIBUTES SA;
2466 int csize = 1;
2467 char *full_command;
2468 int k;
2470 /* compute the total command line length */
2471 k = 0;
2472 while (args[k])
2474 csize += strlen (args[k]) + 1;
2475 k++;
2478 full_command = (char *) xmalloc (csize);
2480 /* Startup info. */
2481 SI.cb = sizeof (STARTUPINFO);
2482 SI.lpReserved = NULL;
2483 SI.lpReserved2 = NULL;
2484 SI.lpDesktop = NULL;
2485 SI.cbReserved2 = 0;
2486 SI.lpTitle = NULL;
2487 SI.dwFlags = 0;
2488 SI.wShowWindow = SW_HIDE;
2490 /* Security attributes. */
2491 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
2492 SA.bInheritHandle = TRUE;
2493 SA.lpSecurityDescriptor = NULL;
2495 /* Prepare the command string. */
2496 strcpy (full_command, command);
2497 strcat (full_command, " ");
2499 k = 1;
2500 while (args[k])
2502 strcat (full_command, args[k]);
2503 strcat (full_command, " ");
2504 k++;
2508 int wsize = csize * 2;
2509 TCHAR *wcommand = (TCHAR *) xmalloc (wsize);
2511 S2WSC (wcommand, full_command, wsize);
2513 free (full_command);
2515 result = CreateProcess
2516 (NULL, wcommand, &SA, NULL, TRUE,
2517 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
2519 free (wcommand);
2522 if (result == TRUE)
2524 CloseHandle (PI.hThread);
2525 *h = PI.hProcess;
2526 *pid = PI.dwProcessId;
2528 else
2530 *h = NULL;
2531 *pid = 0;
2535 static int
2536 win32_wait (int *status)
2538 DWORD exitcode, pid;
2539 HANDLE *hl;
2540 HANDLE h;
2541 int *pidl;
2542 DWORD res;
2543 int hl_len;
2544 int found;
2546 START_WAIT:
2548 if (plist_length == 0)
2550 errno = ECHILD;
2551 return -1;
2554 /* -------------------- critical section -------------------- */
2555 EnterCS();
2557 hl_len = plist_length;
2559 #ifdef CERT
2560 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
2561 memmove (hl, HANDLES_LIST, sizeof (HANDLE) * hl_len);
2562 pidl = (int *) xmalloc (sizeof (int) * hl_len);
2563 memmove (pidl, PID_LIST, sizeof (int) * hl_len);
2564 #else
2565 /* Note that index 0 contains the event handle that is signaled when the
2566 process list has changed */
2567 hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len + 1);
2568 hl[0] = ProcListEvt;
2569 memmove (&hl[1], HANDLES_LIST, sizeof (HANDLE) * hl_len);
2570 pidl = (int *) xmalloc (sizeof (int) * hl_len + 1);
2571 memmove (&pidl[1], PID_LIST, sizeof (int) * hl_len);
2572 hl_len++;
2573 #endif
2575 LeaveCS();
2576 /* -------------------- critical section -------------------- */
2578 res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
2580 /* if the ProcListEvt has been signaled then the list of processes has been
2581 updated to add or remove a handle, just loop over */
2583 if (res - WAIT_OBJECT_0 == 0)
2585 free (hl);
2586 free (pidl);
2587 goto START_WAIT;
2590 h = hl[res - WAIT_OBJECT_0];
2591 GetExitCodeProcess (h, &exitcode);
2592 pid = pidl [res - WAIT_OBJECT_0];
2594 found = __gnat_win32_remove_handle (h, -1);
2596 free (hl);
2597 free (pidl);
2599 /* if not found another process waiting has already handled this process */
2601 if (!found)
2603 goto START_WAIT;
2606 *status = (int) exitcode;
2607 return (int) pid;
2610 #endif
2613 __gnat_portable_no_block_spawn (char *args[] ATTRIBUTE_UNUSED)
2616 #if defined (__vxworks) || defined (__PikeOS__)
2617 /* Not supported. */
2618 return -1;
2620 #elif defined(__DJGPP__)
2621 if (spawnvp (P_WAIT, args[0], args) != 0)
2622 return -1;
2623 else
2624 return 0;
2626 #elif defined (_WIN32)
2628 HANDLE h = NULL;
2629 int pid;
2631 win32_no_block_spawn (args[0], args, &h, &pid);
2632 if (h != NULL)
2634 add_handle (h, pid);
2635 return pid;
2637 else
2638 return -1;
2640 #else
2642 int pid = fork ();
2644 if (pid == 0)
2646 /* The child. */
2647 if (execv (args[0], MAYBE_TO_PTR32 (args)) != 0)
2648 _exit (1);
2651 return pid;
2653 #endif
2657 __gnat_portable_wait (int *process_status)
2659 int status = 0;
2660 int pid = 0;
2662 #if defined (__vxworks) || defined (__PikeOS__)
2663 /* Not sure what to do here, so do nothing but return zero. */
2665 #elif defined (_WIN32)
2667 pid = win32_wait (&status);
2669 #elif defined (__DJGPP__)
2670 /* Child process has already ended in case of DJGPP.
2671 No need to do anything. Just return success. */
2672 #else
2674 pid = waitpid (-1, &status, 0);
2675 status = status & 0xffff;
2676 #endif
2678 *process_status = status;
2679 return pid;
2682 void
2683 __gnat_os_exit (int status)
2685 exit (status);
2689 __gnat_current_process_id (void)
2691 #if defined (__vxworks) || defined (__PikeOS__)
2692 return -1;
2694 #elif defined (_WIN32)
2696 return (int)GetCurrentProcessId();
2698 #else
2700 return (int)getpid();
2701 #endif
2704 /* Locate file on path, that matches a predicate */
2706 char *
2707 __gnat_locate_file_with_predicate (char *file_name, char *path_val,
2708 int (*predicate)(char *))
2710 char *ptr;
2711 char *file_path = (char *) alloca (strlen (file_name) + 1);
2712 int absolute;
2714 /* Return immediately if file_name is empty */
2716 if (*file_name == '\0')
2717 return 0;
2719 /* Remove quotes around file_name if present */
2721 ptr = file_name;
2722 if (*ptr == '"')
2723 ptr++;
2725 strcpy (file_path, ptr);
2727 ptr = file_path + strlen (file_path) - 1;
2729 if (*ptr == '"')
2730 *ptr = '\0';
2732 /* Handle absolute pathnames. */
2734 absolute = __gnat_is_absolute_path (file_path, strlen (file_name));
2736 if (absolute)
2738 if (predicate (file_path))
2739 return xstrdup (file_path);
2741 return 0;
2744 /* If file_name include directory separator(s), try it first as
2745 a path name relative to the current directory */
2746 for (ptr = file_name; *ptr && *ptr != '/' && *ptr != DIR_SEPARATOR; ptr++)
2749 if (*ptr != 0)
2751 if (predicate (file_name))
2752 return xstrdup (file_name);
2755 if (path_val == 0)
2756 return 0;
2759 /* The result has to be smaller than path_val + file_name. */
2760 char *file_path =
2761 (char *) alloca (strlen (path_val) + strlen (file_name) + 2);
2763 for (;;)
2765 /* Skip the starting quote */
2767 if (*path_val == '"')
2768 path_val++;
2770 for (ptr = file_path; *path_val && *path_val != PATH_SEPARATOR; )
2771 *ptr++ = *path_val++;
2773 /* If directory is empty, it is the current directory*/
2775 if (ptr == file_path)
2777 *ptr = '.';
2779 else
2780 ptr--;
2782 /* Skip the ending quote */
2784 if (*ptr == '"')
2785 ptr--;
2787 if (*ptr != '/' && *ptr != DIR_SEPARATOR)
2788 *++ptr = DIR_SEPARATOR;
2790 strcpy (++ptr, file_name);
2792 if (predicate (file_path))
2793 return xstrdup (file_path);
2795 if (*path_val == 0)
2796 return 0;
2798 /* Skip path separator */
2800 path_val++;
2804 return 0;
2807 /* Locate an executable file, give a Path value. */
2809 char *
2810 __gnat_locate_executable_file (char *file_name, char *path_val)
2812 return __gnat_locate_file_with_predicate
2813 (file_name, path_val, &__gnat_is_executable_file);
2816 /* Locate a regular file, give a Path value. */
2818 char *
2819 __gnat_locate_regular_file (char *file_name, char *path_val)
2821 return __gnat_locate_file_with_predicate
2822 (file_name, path_val, &__gnat_is_regular_file);
2825 /* Locate an executable given a Path argument. This routine is only used by
2826 gnatbl and should not be used otherwise. Use locate_exec_on_path
2827 instead. */
2829 char *
2830 __gnat_locate_exec (char *exec_name, char *path_val)
2832 char *ptr;
2833 if (!strstr (exec_name, HOST_EXECUTABLE_SUFFIX))
2835 char *full_exec_name =
2836 (char *) alloca
2837 (strlen (exec_name) + strlen (HOST_EXECUTABLE_SUFFIX) + 1);
2839 strcpy (full_exec_name, exec_name);
2840 strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX);
2841 ptr = __gnat_locate_executable_file (full_exec_name, path_val);
2843 if (ptr == 0)
2844 return __gnat_locate_executable_file (exec_name, path_val);
2845 return ptr;
2847 else
2848 return __gnat_locate_executable_file (exec_name, path_val);
2851 /* Locate an executable using the Systems default PATH. */
2853 char *
2854 __gnat_locate_exec_on_path (char *exec_name)
2856 char *apath_val;
2858 #if defined (_WIN32)
2859 TCHAR *wpath_val = _tgetenv (_T("PATH"));
2860 TCHAR *wapath_val;
2861 /* In Win32 systems we expand the PATH as for XP environment
2862 variables are not automatically expanded. We also prepend the
2863 ".;" to the path to match normal NT path search semantics */
2865 #define EXPAND_BUFFER_SIZE 32767
2867 wapath_val = (TCHAR *) alloca (EXPAND_BUFFER_SIZE);
2869 wapath_val [0] = '.';
2870 wapath_val [1] = ';';
2872 DWORD res = ExpandEnvironmentStrings
2873 (wpath_val, &wapath_val[2], EXPAND_BUFFER_SIZE - 2);
2875 if (!res) wapath_val [0] = _T('\0');
2877 apath_val = (char *) alloca (EXPAND_BUFFER_SIZE);
2879 WS2SC (apath_val, wapath_val, EXPAND_BUFFER_SIZE);
2881 #else
2882 const char *path_val = getenv ("PATH");
2884 /* If PATH is not defined, proceed with __gnat_locate_exec anyway, so we can
2885 find files that contain directory names. */
2887 if (path_val == NULL) path_val = "";
2888 apath_val = (char *) alloca (strlen (path_val) + 1);
2889 strcpy (apath_val, path_val);
2890 #endif
2892 return __gnat_locate_exec (exec_name, apath_val);
2895 /* Dummy functions for Osint import for non-VMS systems.
2896 ??? To be removed. */
2899 __gnat_to_canonical_file_list_init (char *dirspec ATTRIBUTE_UNUSED,
2900 int onlydirs ATTRIBUTE_UNUSED)
2902 return 0;
2905 char *
2906 __gnat_to_canonical_file_list_next (void)
2908 static char empty[] = "";
2909 return empty;
2912 void
2913 __gnat_to_canonical_file_list_free (void)
2917 char *
2918 __gnat_to_canonical_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2920 return dirspec;
2923 char *
2924 __gnat_to_canonical_file_spec (char *filespec)
2926 return filespec;
2929 char *
2930 __gnat_to_canonical_path_spec (char *pathspec)
2932 return pathspec;
2935 char *
2936 __gnat_to_host_dir_spec (char *dirspec, int prefixflag ATTRIBUTE_UNUSED)
2938 return dirspec;
2941 char *
2942 __gnat_to_host_file_spec (char *filespec)
2944 return filespec;
2947 void
2948 __gnat_adjust_os_resource_limits (void)
2952 #if defined (__mips_vxworks)
2954 _flush_cache (void)
2956 CACHE_USER_FLUSH (0, ENTIRE_CACHE);
2958 #endif
2960 #if defined (_WIN32)
2961 int __gnat_argument_needs_quote = 1;
2962 #else
2963 int __gnat_argument_needs_quote = 0;
2964 #endif
2966 /* This option is used to enable/disable object files handling from the
2967 binder file by the GNAT Project module. For example, this is disabled on
2968 Windows (prior to GCC 3.4) as it is already done by the mdll module.
2969 Stating with GCC 3.4 the shared libraries are not based on mdll
2970 anymore as it uses the GCC's -shared option */
2971 #if defined (_WIN32) \
2972 && ((__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)))
2973 int __gnat_prj_add_obj_files = 0;
2974 #else
2975 int __gnat_prj_add_obj_files = 1;
2976 #endif
2978 /* char used as prefix/suffix for environment variables */
2979 #if defined (_WIN32)
2980 char __gnat_environment_char = '%';
2981 #else
2982 char __gnat_environment_char = '$';
2983 #endif
2985 /* This functions copy the file attributes from a source file to a
2986 destination file.
2988 mode = 0 : In this mode copy only the file time stamps (last access and
2989 last modification time stamps).
2991 mode = 1 : In this mode, time stamps and read/write/execute attributes are
2992 copied.
2994 mode = 2 : In this mode, only read/write/execute attributes are copied
2996 Returns 0 if operation was successful and -1 in case of error. */
2999 __gnat_copy_attribs (char *from ATTRIBUTE_UNUSED, char *to ATTRIBUTE_UNUSED,
3000 int mode ATTRIBUTE_UNUSED)
3002 #if (defined (__vxworks) && _WRS_VXWORKS_MAJOR < 6)
3003 return -1;
3005 #elif defined (_WIN32)
3006 TCHAR wfrom [GNAT_MAX_PATH_LEN + 2];
3007 TCHAR wto [GNAT_MAX_PATH_LEN + 2];
3008 BOOL res;
3009 FILETIME fct, flat, flwt;
3010 HANDLE hfrom, hto;
3012 S2WSC (wfrom, from, GNAT_MAX_PATH_LEN + 2);
3013 S2WSC (wto, to, GNAT_MAX_PATH_LEN + 2);
3015 /* Do we need to copy the timestamp ? */
3017 if (mode != 2) {
3018 /* retrieve from times */
3020 hfrom = CreateFile
3021 (wfrom, GENERIC_READ, 0, NULL, OPEN_EXISTING,
3022 FILE_ATTRIBUTE_NORMAL, NULL);
3024 if (hfrom == INVALID_HANDLE_VALUE)
3025 return -1;
3027 res = GetFileTime (hfrom, &fct, &flat, &flwt);
3029 CloseHandle (hfrom);
3031 if (res == 0)
3032 return -1;
3034 /* retrieve from times */
3036 hto = CreateFile
3037 (wto, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
3038 FILE_ATTRIBUTE_NORMAL, NULL);
3040 if (hto == INVALID_HANDLE_VALUE)
3041 return -1;
3043 res = SetFileTime (hto, NULL, &flat, &flwt);
3045 CloseHandle (hto);
3047 if (res == 0)
3048 return -1;
3051 /* Do we need to copy the permissions ? */
3052 /* Set file attributes in full mode. */
3054 if (mode != 0)
3056 DWORD attribs = GetFileAttributes (wfrom);
3058 if (attribs == INVALID_FILE_ATTRIBUTES)
3059 return -1;
3061 res = SetFileAttributes (wto, attribs);
3062 if (res == 0)
3063 return -1;
3066 return 0;
3068 #else
3069 GNAT_STRUCT_STAT fbuf;
3070 struct utimbuf tbuf;
3072 if (GNAT_STAT (from, &fbuf) == -1) {
3073 return -1;
3076 /* Do we need to copy timestamp ? */
3077 if (mode != 2) {
3078 tbuf.actime = fbuf.st_atime;
3079 tbuf.modtime = fbuf.st_mtime;
3081 if (utime (to, &tbuf) == -1) {
3082 return -1;
3086 /* Do we need to copy file permissions ? */
3087 if (mode != 0 && (chmod (to, fbuf.st_mode) == -1)) {
3088 return -1;
3091 return 0;
3092 #endif
3096 __gnat_lseek (int fd, long offset, int whence)
3098 return (int) lseek (fd, offset, whence);
3101 /* This function returns the major version number of GCC being used. */
3103 get_gcc_version (void)
3105 #ifdef IN_RTS
3106 return __GNUC__;
3107 #else
3108 return (int) (version_string[0] - '0');
3109 #endif
3113 * Set Close_On_Exec as indicated.
3114 * Note: this is used for both GNAT.OS_Lib and GNAT.Sockets.
3118 __gnat_set_close_on_exec (int fd ATTRIBUTE_UNUSED,
3119 int close_on_exec_p ATTRIBUTE_UNUSED)
3121 #if defined (F_GETFD) && defined (FD_CLOEXEC) && ! defined (__vxworks)
3122 int flags = fcntl (fd, F_GETFD, 0);
3123 if (flags < 0)
3124 return flags;
3125 if (close_on_exec_p)
3126 flags |= FD_CLOEXEC;
3127 else
3128 flags &= ~FD_CLOEXEC;
3129 return fcntl (fd, F_SETFD, flags);
3130 #elif defined(_WIN32)
3131 HANDLE h = (HANDLE) _get_osfhandle (fd);
3132 if (h == (HANDLE) -1)
3133 return -1;
3134 if (close_on_exec_p)
3135 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT, 0);
3136 return ! SetHandleInformation (h, HANDLE_FLAG_INHERIT,
3137 HANDLE_FLAG_INHERIT);
3138 #else
3139 /* TODO: Unimplemented. */
3140 return -1;
3141 #endif
3144 /* Indicates if platforms supports automatic initialization through the
3145 constructor mechanism */
3147 __gnat_binder_supports_auto_init (void)
3149 return 1;
3152 /* Indicates that Stand-Alone Libraries are automatically initialized through
3153 the constructor mechanism */
3155 __gnat_sals_init_using_constructors (void)
3157 #if defined (__vxworks) || defined (__Lynx__)
3158 return 0;
3159 #else
3160 return 1;
3161 #endif
3164 #if defined (__linux__) || defined (__ANDROID__)
3165 /* There is no function in the glibc to retrieve the LWP of the current
3166 thread. We need to do a system call in order to retrieve this
3167 information. */
3168 #include <sys/syscall.h>
3169 void *
3170 __gnat_lwp_self (void)
3172 return (void *) syscall (__NR_gettid);
3174 #endif
3176 #if defined (__APPLE__)
3177 #include <mach/thread_info.h>
3178 #include <mach/mach_init.h>
3179 #include <mach/thread_act.h>
3181 /* System-wide thread identifier. Note it could be truncated on 32 bit
3182 hosts.
3183 Previously was: pthread_mach_thread_np (pthread_self ()). */
3184 void *
3185 __gnat_lwp_self (void)
3187 thread_identifier_info_data_t data;
3188 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
3189 kern_return_t kret;
3191 kret = thread_info (mach_thread_self (), THREAD_IDENTIFIER_INFO,
3192 (thread_info_t) &data, &count);
3193 if (kret == KERN_SUCCESS)
3194 return (void *)(uintptr_t)data.thread_id;
3195 else
3196 return 0;
3198 #endif
3200 #if defined (__linux__)
3201 #include <sched.h>
3203 /* glibc versions earlier than 2.7 do not define the routines to handle
3204 dynamically allocated CPU sets. For these targets, we use the static
3205 versions. */
3207 #ifdef CPU_ALLOC
3209 /* Dynamic cpu sets */
3211 cpu_set_t *
3212 __gnat_cpu_alloc (size_t count)
3214 return CPU_ALLOC (count);
3217 size_t
3218 __gnat_cpu_alloc_size (size_t count)
3220 return CPU_ALLOC_SIZE (count);
3223 void
3224 __gnat_cpu_free (cpu_set_t *set)
3226 CPU_FREE (set);
3229 void
3230 __gnat_cpu_zero (size_t count, cpu_set_t *set)
3232 CPU_ZERO_S (count, set);
3235 void
3236 __gnat_cpu_set (int cpu, size_t count, cpu_set_t *set)
3238 /* Ada handles CPU numbers starting from 1, while C identifies the first
3239 CPU by a 0, so we need to adjust. */
3240 CPU_SET_S (cpu - 1, count, set);
3243 #else /* !CPU_ALLOC */
3245 /* Static cpu sets */
3247 cpu_set_t *
3248 __gnat_cpu_alloc (size_t count ATTRIBUTE_UNUSED)
3250 return (cpu_set_t *) xmalloc (sizeof (cpu_set_t));
3253 size_t
3254 __gnat_cpu_alloc_size (size_t count ATTRIBUTE_UNUSED)
3256 return sizeof (cpu_set_t);
3259 void
3260 __gnat_cpu_free (cpu_set_t *set)
3262 free (set);
3265 void
3266 __gnat_cpu_zero (size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3268 CPU_ZERO (set);
3271 void
3272 __gnat_cpu_set (int cpu, size_t count ATTRIBUTE_UNUSED, cpu_set_t *set)
3274 /* Ada handles CPU numbers starting from 1, while C identifies the first
3275 CPU by a 0, so we need to adjust. */
3276 CPU_SET (cpu - 1, set);
3278 #endif /* !CPU_ALLOC */
3279 #endif /* __linux__ */
3281 /* Return the load address of the executable, or 0 if not known. In the
3282 specific case of error, (void *)-1 can be returned. Beware: this unit may
3283 be in a shared library. As low-level units are needed, we allow #include
3284 here. */
3286 #if defined (__APPLE__)
3287 #include <mach-o/dyld.h>
3288 #endif
3290 const void *
3291 __gnat_get_executable_load_address (void)
3293 #if defined (__APPLE__)
3294 return _dyld_get_image_header (0);
3296 #elif 0 && defined (__linux__)
3297 /* Currently disabled as it needs at least -ldl. */
3298 struct link_map *map = _r_debug.r_map;
3300 return (const void *)map->l_addr;
3302 #else
3303 return NULL;
3304 #endif
3307 void
3308 __gnat_kill (int pid, int sig, int close ATTRIBUTE_UNUSED)
3310 #if defined(_WIN32)
3311 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
3312 if (h == NULL)
3313 return;
3314 if (sig == 9)
3316 TerminateProcess (h, 1);
3318 else if (sig == SIGINT)
3319 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
3320 else if (sig == SIGBREAK)
3321 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
3322 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
3323 up process groups at start time which we don't do; treating SIGINT is just
3324 not possible apparently. So we really only support signal 9. Fortunately
3325 that's all we use in GNAT.Expect */
3327 CloseHandle (h);
3328 #elif defined (__vxworks)
3329 /* Not implemented */
3330 #else
3331 kill (pid, sig);
3332 #endif
3335 void __gnat_killprocesstree (int pid, int sig_num)
3337 #if defined(_WIN32)
3338 PROCESSENTRY32 pe;
3340 memset(&pe, 0, sizeof(PROCESSENTRY32));
3341 pe.dwSize = sizeof(PROCESSENTRY32);
3343 HANDLE hSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
3345 /* cannot take snapshot, just kill the parent process */
3347 if (hSnap == INVALID_HANDLE_VALUE)
3349 __gnat_kill (pid, sig_num, 1);
3350 return;
3353 if (Process32First(hSnap, &pe))
3355 BOOL bContinue = TRUE;
3357 /* kill child processes first */
3359 while (bContinue)
3361 if (pe.th32ParentProcessID == (DWORD)pid)
3362 __gnat_killprocesstree (pe.th32ProcessID, sig_num);
3364 bContinue = Process32Next (hSnap, &pe);
3368 CloseHandle (hSnap);
3370 /* kill process */
3372 __gnat_kill (pid, sig_num, 1);
3374 #elif defined (__vxworks)
3375 /* not implemented */
3377 #elif defined (__linux__)
3378 DIR *dir;
3379 struct dirent *d;
3381 /* read all processes' pid and ppid */
3383 dir = opendir ("/proc");
3385 /* cannot open proc, just kill the parent process */
3387 if (!dir)
3389 __gnat_kill (pid, sig_num, 1);
3390 return;
3393 /* kill child processes first */
3395 while ((d = readdir (dir)) != NULL)
3397 if ((d->d_type & DT_DIR) == DT_DIR)
3399 char statfile[64] = { 0 };
3400 int _pid, _ppid;
3402 /* read /proc/<PID>/stat */
3404 strncpy (statfile, "/proc/", sizeof(statfile));
3405 strncat (statfile, d->d_name, sizeof(statfile));
3406 strncat (statfile, "/stat", sizeof(statfile));
3408 FILE *fd = fopen (statfile, "r");
3410 if (fd)
3412 const int match = fscanf (fd, "%d %*s %*s %d", &_pid, &_ppid);
3413 fclose (fd);
3415 if (match == 2 && _ppid == pid)
3416 __gnat_killprocesstree (_pid, sig_num);
3421 closedir (dir);
3423 /* kill process */
3425 __gnat_kill (pid, sig_num, 1);
3426 #else
3427 __gnat_kill (pid, sig_num, 1);
3428 #endif
3429 /* Note on Solaris it is possible to read /proc/<PID>/status.
3430 The 5th and 6th words are the pid and the 7th and 8th the ppid.
3431 See: /usr/include/sys/procfs.h (struct pstatus).
3435 #ifdef __cplusplus
3437 #endif