xref: /reactos/sdk/lib/ucrt/exec/system.cpp (revision fe11f7a2)
1 //
2 // system.cpp
3 //
4 //      Copyright (c) Microsoft Corporation.  All rights reserved.
5 //
6 // Defines the system() family of functions, which execute a command via the
7 // shell.
8 //
9 #include <corecrt_internal.h>
10 #include <corecrt_internal_traits.h>
11 #include <process.h>
12 #include <io.h>
13 #include <stdlib.h>
14 #include <errno.h>
15 
16 
17 
18 // Executes a command via the shell.  If the command is null, attempts to execute
19 // the command processor specified by the %COMSPEC% environment variable.  If
20 // that fails, attempts to execute cmd.exe.
21 template <typename Character>
22 static int __cdecl common_system(Character const* const command) throw()
23 {
24     typedef __crt_char_traits<Character> traits;
25 
26     static Character const comspec_name[] = { 'C', 'O', 'M', 'S', 'P', 'E', 'C', '\0' };
27     static Character const cmd_exe[]      = { 'c', 'm', 'd', '.', 'e', 'x', 'e', '\0' };
28     static Character const slash_c[]      = { '/', 'c', '\0' };
29 
30     __crt_unique_heap_ptr<Character> comspec_value;
31     _ERRCHECK_EINVAL(traits::tdupenv_s_crt(comspec_value.get_address_of(), nullptr, comspec_name));
32 
33     // If the command is null, return TRUE only if %COMSPEC% is set and the file
34     // to which it points exists.
35     if (!command)
36     {
37         if (!comspec_value)
38             return 0;
39 
40         return traits::taccess_s(comspec_value.get(), 0) == 0;
41     }
42 
43     _ASSERTE(command[0] != '\0');
44 
45     Character const* arguments[4] =
46     {
47         comspec_value.get(),
48         slash_c,
49         command,
50         nullptr
51     };
52 
53     if (comspec_value)
54     {
55         errno_t const saved_errno = errno;
56         errno = 0;
57 
58         int const result = static_cast<int>(traits::tspawnve(_P_WAIT, arguments[0], arguments, nullptr));
59         if (result != -1)
60         {
61             errno = saved_errno;
62             return result;
63         }
64 
65         if (errno != ENOENT && errno != EACCES)
66         {
67             return result;
68         }
69 
70         // If the error wasn't one of those two errors, try again with cmd.exe...
71         errno = saved_errno;
72     }
73 
74    arguments[0] = cmd_exe;
75    return static_cast<int>(traits::tspawnvpe(_P_WAIT, arguments[0], arguments, nullptr));
76 }
77 
78 extern "C" int __cdecl system(char const* const command)
79 {
80     return common_system(command);
81 }
82 
83 extern "C" int __cdecl _wsystem(wchar_t const* const command)
84 {
85     return common_system(command);
86 }
87