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