xref: /aosp_15_r20/external/OpenCL-CTS/test_common/harness/os_helpers.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "os_helpers.h"
17 #include "errorHelpers.h"
18 
19 // =================================================================================================
20 // C++ interface.
21 // =================================================================================================
22 
23 #include <cerrno> // errno, error constants
24 #include <climits> // PATH_MAX
25 #include <cstdlib> // abort, _splitpath, _makepath
26 #include <cstring> // strdup, strerror_r
27 #include <sstream>
28 
29 #include <vector>
30 
31 #if defined(__ANDROID__)
32 #include <android/api-level.h>
33 #include "harness/mt19937.h"
34 #endif
35 
36 #if !defined(_WIN32)
37 #if defined(__APPLE__)
38 #include <sys/sysctl.h>
39 #endif
40 #include <unistd.h>
41 #endif
42 
43 
44 #define CHECK_PTR(ptr)                                                         \
45     if ((ptr) == NULL)                                                         \
46     {                                                                          \
47         abort();                                                               \
48     }
49 
50 typedef std::vector<char> buffer_t;
51 
52 #if !defined(PATH_MAX)
53 #define PATH_MAX 1000
54 #endif
55 
56 int const _size = PATH_MAX + 1; // Initial buffer size for path.
57 int const _count = 8; // How many times we will try to double buffer size.
58 
59 // -------------------------------------------------------------------------------------------------
60 // MacOS X
61 // -------------------------------------------------------------------------------------------------
62 
63 #if defined(__APPLE__)
64 
65 
66 #include <mach-o/dyld.h> // _NSGetExecutablePath
67 #include <libgen.h> // dirname
68 
69 
70 static std::string
_err_msg(int err,int level)71 _err_msg(int err, // Error number (e. g. errno).
72          int level // Nesting level, for avoiding infinite recursion.
73 )
74 {
75 
76     /*
77         There are 3 incompatible versions of strerror_r:
78 
79             char * strerror_r( int, char *, size_t );  // GNU version
80             int    strerror_r( int, char *, size_t );  // BSD version
81             int    strerror_r( int, char *, size_t );  // XSI version
82 
83         BSD version returns error code, while XSI version returns 0 or -1 and
84        sets errno.
85 
86     */
87 
88     // BSD version of strerror_r.
89     buffer_t buffer(100);
90     int count = _count;
91     for (;;)
92     {
93         int rc = strerror_r(err, &buffer.front(), buffer.size());
94         if (rc == EINVAL)
95         {
96             // Error code is not recognized, but anyway we got the message.
97             return &buffer.front();
98         }
99         else if (rc == ERANGE)
100         {
101             // Buffer is not enough.
102             if (count > 0)
103             {
104                 // Enlarge the buffer.
105                 --count;
106                 buffer.resize(buffer.size() * 2);
107             }
108             else
109             {
110                 std::stringstream ostr;
111                 ostr << "Error " << err << " "
112                      << "(Getting error message failed: "
113                      << "Buffer of " << buffer.size()
114                      << " bytes is still too small"
115                      << ")";
116                 return ostr.str();
117             }; // if
118         }
119         else if (rc == 0)
120         {
121             // We got the message.
122             return &buffer.front();
123         }
124         else
125         {
126             std::stringstream ostr;
127             ostr << "Error " << err << " "
128                  << "(Getting error message failed: "
129                  << (level < 2 ? _err_msg(rc, level + 1) : "Oops") << ")";
130             return ostr.str();
131         }; // if
132     }; // forever
133 
134 } // _err_msg
135 
136 
dir_sep()137 std::string dir_sep() { return "/"; } // dir_sep
138 
139 
exe_path()140 std::string exe_path()
141 {
142     buffer_t path(_size);
143     int count = _count;
144     for (;;)
145     {
146         uint32_t size = path.size();
147         int rc = _NSGetExecutablePath(&path.front(), &size);
148         if (rc == 0)
149         {
150             break;
151         }; // if
152         if (count > 0)
153         {
154             --count;
155             path.resize(size);
156         }
157         else
158         {
159             log_error("ERROR: Getting executable path failed: "
160                       "_NSGetExecutablePath failed: Buffer of %lu bytes is "
161                       "still too small\n",
162                       (unsigned long)path.size());
163             exit(2);
164         }; // if
165     }; // forever
166     return &path.front();
167 } // exe_path
168 
169 
exe_dir()170 std::string exe_dir()
171 {
172     std::string path = exe_path();
173     // We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its
174     // argument.
175     buffer_t buffer(path.c_str(),
176                     path.c_str() + path.size() + 1); // Copy with trailing zero.
177     return dirname(&buffer.front());
178 } // exe_dir
179 
180 
181 #endif // __APPLE__
182 
183 // -------------------------------------------------------------------------------------------------
184 // Linux
185 // -------------------------------------------------------------------------------------------------
186 
187 #if defined(__linux__)
188 
189 
190 #include <cerrno> // errno
191 #include <libgen.h> // dirname
192 #include <unistd.h> // readlink
193 
194 
_err_msg(int err,int level)195 static std::string _err_msg(int err, int level)
196 {
197 
198     /*
199         There are 3 incompatible versions of strerror_r:
200 
201             char * strerror_r( int, char *, size_t );  // GNU version
202             int    strerror_r( int, char *, size_t );  // BSD version
203             int    strerror_r( int, char *, size_t );  // XSI version
204 
205         BSD version returns error code, while XSI version returns 0 or -1 and
206        sets errno.
207 
208     */
209 
210 #if (defined(__ANDROID__) && __ANDROID_API__ < 23)                             \
211     || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
212 
213 // XSI version of strerror_r.
214 #warning Not tested!
215     buffer_t buffer(200);
216     int count = _count;
217     for (;;)
218     {
219         int rc = strerror_r(err, &buffer.front(), buffer.size());
220         if (rc == -1)
221         {
222             int _err = errno;
223             if (_err == ERANGE)
224             {
225                 if (count > 0)
226                 {
227                     // Enlarge the buffer.
228                     --count;
229                     buffer.resize(buffer.size() * 2);
230                 }
231                 else
232                 {
233                     std::stringstream ostr;
234                     ostr << "Error " << err << " "
235                          << "(Getting error message failed: "
236                          << "Buffer of " << buffer.size()
237                          << " bytes is still too small"
238                          << ")";
239                     return ostr.str();
240                 }; // if
241             }
242             else
243             {
244                 std::stringstream ostr;
245                 ostr << "Error " << err << " "
246                      << "(Getting error message failed: "
247                      << (level < 2 ? _err_msg(_err, level + 1) : "Oops") << ")";
248                 return ostr.str();
249             }; // if
250         }
251         else
252         {
253             // We got the message.
254             return &buffer.front();
255         }; // if
256     }; // forever
257 
258 #else
259 
260     // GNU version of strerror_r.
261     char buffer[2000];
262     return strerror_r(err, buffer, sizeof(buffer));
263 
264 #endif
265 
266 } // _err_msg
267 
268 
dir_sep()269 std::string dir_sep() { return "/"; } // dir_sep
270 
271 
exe_path()272 std::string exe_path()
273 {
274 
275     static std::string const exe = "/proc/self/exe";
276 
277     buffer_t path(_size);
278     int count = _count; // Max number of iterations.
279 
280     for (;;)
281     {
282 
283         ssize_t len = readlink(exe.c_str(), &path.front(), path.size());
284 
285         if (len < 0)
286         {
287             // Oops.
288             int err = errno;
289             log_error("ERROR: Getting executable path failed: "
290                       "Reading symlink `%s' failed: %s\n",
291                       exe.c_str(), err_msg(err).c_str());
292             exit(2);
293         }; // if
294 
295         if (static_cast<size_t>(len) < path.size())
296         {
297             // We got the path.
298             path.resize(len);
299             break;
300         }; // if
301 
302         // Oops, buffer is too small.
303         if (count > 0)
304         {
305             --count;
306             // Enlarge the buffer.
307             path.resize(path.size() * 2);
308         }
309         else
310         {
311             log_error("ERROR: Getting executable path failed: "
312                       "Reading symlink `%s' failed: Buffer of %lu bytes is "
313                       "still too small\n",
314                       exe.c_str(), (unsigned long)path.size());
315             exit(2);
316         }; // if
317 
318     }; // forever
319 
320     return std::string(&path.front(), path.size());
321 
322 } // exe_path
323 
324 
exe_dir()325 std::string exe_dir()
326 {
327     std::string path = exe_path();
328     // We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its
329     // argument.
330     buffer_t buffer(path.c_str(),
331                     path.c_str() + path.size() + 1); // Copy with trailing zero.
332     return dirname(&buffer.front());
333 } // exe_dir
334 
335 #endif // __linux__
336 
337 // -------------------------------------------------------------------------------------------------
338 // MS Windows
339 // -------------------------------------------------------------------------------------------------
340 
341 #if defined(_WIN32)
342 
343 
344 #include <windows.h>
345 
346 #include <cctype>
347 #include <algorithm>
348 
349 
_err_msg(int err,int level)350 static std::string _err_msg(int err, int level)
351 {
352 
353     std::string msg;
354 
355     LPSTR buffer = NULL;
356     DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
357         | FORMAT_MESSAGE_IGNORE_INSERTS;
358 
359     DWORD len = FormatMessageA(flags, NULL, err, LANG_USER_DEFAULT,
360                                reinterpret_cast<LPSTR>(&buffer), 0, NULL);
361 
362     if (buffer == NULL || len == 0)
363     {
364 
365         int _err = GetLastError();
366         char str[1024] = { 0 };
367         snprintf(str, sizeof(str),
368                  "Error 0x%08x (Getting error message failed: %s )", err,
369                  (level < 2 ? _err_msg(_err, level + 1).c_str() : "Oops"));
370         msg = std::string(str);
371     }
372     else
373     {
374 
375         // Trim trailing whitespace (including `\r' and `\n').
376         while (len > 0 && isspace(buffer[len - 1]))
377         {
378             --len;
379         }; // while
380 
381         // Drop trailing full stop.
382         if (len > 0 && buffer[len - 1] == '.')
383         {
384             --len;
385         }; // if
386 
387         msg.assign(buffer, len);
388 
389     }; // if
390 
391     if (buffer != NULL)
392     {
393         LocalFree(buffer);
394     }; // if
395 
396     return msg;
397 
398 } // _get_err_msg
399 
400 
dir_sep()401 std::string dir_sep() { return "\\"; } // dir_sep
402 
403 
exe_path()404 std::string exe_path()
405 {
406 
407     buffer_t path(_size);
408     int count = _count;
409 
410     for (;;)
411     {
412 
413         DWORD len = GetModuleFileNameA(NULL, &path.front(),
414                                        static_cast<DWORD>(path.size()));
415 
416         if (len == 0)
417         {
418             int err = GetLastError();
419             log_error("ERROR: Getting executable path failed: %s\n",
420                       err_msg(err).c_str());
421             exit(2);
422         }; // if
423 
424         if (len < path.size())
425         {
426             path.resize(len);
427             break;
428         }; // if
429 
430         // Buffer too small.
431         if (count > 0)
432         {
433             --count;
434             path.resize(path.size() * 2);
435         }
436         else
437         {
438             log_error("ERROR: Getting executable path failed: "
439                       "Buffer of %lu bytes is still too small\n",
440                       (unsigned long)path.size());
441             exit(2);
442         }; // if
443 
444     }; // forever
445 
446     return std::string(&path.front(), path.size());
447 
448 } // exe_path
449 
450 
exe_dir()451 std::string exe_dir()
452 {
453 
454     std::string exe = exe_path();
455     int count = 0;
456 
457     // Splitting path into components.
458     buffer_t drv(_MAX_DRIVE);
459     buffer_t dir(_MAX_DIR);
460     count = _count;
461 #if defined(_MSC_VER)
462     for (;;)
463     {
464         int rc =
465             _splitpath_s(exe.c_str(), &drv.front(), drv.size(), &dir.front(),
466                          dir.size(), NULL, 0, // We need neither name
467                          NULL, 0 // nor extension
468             );
469         if (rc == 0)
470         {
471             break;
472         }
473         else if (rc == ERANGE)
474         {
475             if (count > 0)
476             {
477                 --count;
478                 // Buffer is too small, but it is not clear which one.
479                 // So we have to enlarge all.
480                 drv.resize(drv.size() * 2);
481                 dir.resize(dir.size() * 2);
482             }
483             else
484             {
485                 log_error("ERROR: Getting executable path failed: "
486                           "Splitting path `%s' to components failed: "
487                           "Buffers of %lu and %lu bytes are still too small\n",
488                           exe.c_str(), (unsigned long)drv.size(),
489                           (unsigned long)dir.size());
490                 exit(2);
491             }; // if
492         }
493         else
494         {
495             log_error("ERROR: Getting executable path failed: "
496                       "Splitting path `%s' to components failed: %s\n",
497                       exe.c_str(), err_msg(rc).c_str());
498             exit(2);
499         }; // if
500     }; // forever
501 
502 #else // __MINGW32__
503 
504     // MinGW does not have the "secure" _splitpath_s, use the insecure version
505     // instead.
506     _splitpath(exe.c_str(), &drv.front(), &dir.front(),
507                NULL, // We need neither name
508                NULL // nor extension
509     );
510 #endif // __MINGW32__
511 
512     // Combining components back to path.
513     // I failed with "secure" `_makepath_s'. If buffer is too small, instead of
514     // returning ERANGE, `_makepath_s' pops up dialog box and offers to debug
515     // the program. D'oh! So let us try to guess the size of result and go with
516     // insecure `_makepath'.
517     buffer_t path(std::max(drv.size() + dir.size(), size_t(_MAX_PATH)) + 10);
518     _makepath(&path.front(), &drv.front(), &dir.front(), NULL, NULL);
519 
520     return &path.front();
521 
522 } // exe_dir
523 
524 
525 #endif // _WIN32
526 
527 
err_msg(int err)528 std::string err_msg(int err) { return _err_msg(err, 0); } // err_msg
529 
530 
531 // =================================================================================================
532 // C interface.
533 // =================================================================================================
534 
535 
get_err_msg(int err)536 char* get_err_msg(int err)
537 {
538     char* msg = strdup(err_msg(err).c_str());
539     CHECK_PTR(msg);
540     return msg;
541 } // get_err_msg
542 
543 
get_dir_sep()544 char* get_dir_sep()
545 {
546     char* sep = strdup(dir_sep().c_str());
547     CHECK_PTR(sep);
548     return sep;
549 } // get_dir_sep
550 
551 
get_exe_path()552 char* get_exe_path()
553 {
554     char* path = strdup(exe_path().c_str());
555     CHECK_PTR(path);
556     return path;
557 } // get_exe_path
558 
559 
get_exe_dir()560 char* get_exe_dir()
561 {
562     char* dir = strdup(exe_dir().c_str());
563     CHECK_PTR(dir);
564     return dir;
565 } // get_exe_dir
566 
567 
get_temp_filename()568 char* get_temp_filename()
569 {
570     char gFileName[256] = "";
571     // Create a unique temporary file to allow parallel executed tests.
572 #if (defined(__linux__) || defined(__APPLE__)) && (!defined(__ANDROID__))
573     sprintf(gFileName, "/tmp/tmpfile.XXXXXX");
574     int fd = mkstemp(gFileName);
575     if (fd == -1) return strdup(gFileName);
576     close(fd);
577 #elif defined(_WIN32)
578     UINT ret = GetTempFileName(".", "tmp", 0, gFileName);
579     if (ret == 0) return gFileName;
580 #else
581     MTdata d = init_genrand((cl_uint)time(NULL));
582     sprintf(gFileName, "tmpfile.%u", genrand_int32(d));
583 #endif
584 
585     char* fn = strdup(gFileName);
586     CHECK_PTR(fn);
587     return fn;
588 }
589 
590 
591 // end of file //
592