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