1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <spawn.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34 
35 #include "private/__bionic_get_shell_path.h"
36 #include "private/ScopedSignalBlocker.h"
37 #include "private/ScopedSignalHandler.h"
38 
system(const char * command)39 int system(const char* command) {
40   // "The system() function shall always return non-zero when command is NULL."
41   // http://pubs.opengroup.org/onlinepubs/9699919799/functions/system.html
42   if (command == nullptr) return 1;
43 
44   ScopedSignalBlocker sigchld_blocker(SIGCHLD);
45   ScopedSignalHandler sigint_ignorer(SIGINT, SIG_IGN);
46   ScopedSignalHandler sigquit_ignorer(SIGQUIT, SIG_IGN);
47 
48   sigset64_t default_mask = {};
49   if (sigint_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGINT);
50   if (sigquit_ignorer.old_action_.sa_handler != SIG_IGN) sigaddset64(&default_mask, SIGQUIT);
51 
52   static constexpr int flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
53   posix_spawnattr_t attributes;
54   if ((errno = posix_spawnattr_init(&attributes))) return -1;
55   if ((errno = posix_spawnattr_setsigdefault64(&attributes, &default_mask))) return -1;
56   if ((errno = posix_spawnattr_setsigmask64(&attributes, &sigchld_blocker.old_set_))) return -1;
57   if ((errno = posix_spawnattr_setflags(&attributes, flags))) return -1;
58 
59   const char* argv[] = {"sh", "-c", "--", command, nullptr};
60   pid_t child;
61   if ((errno = posix_spawn(&child, __bionic_get_shell_path(), nullptr, &attributes,
62                            const_cast<char**>(argv), environ)) != 0) {
63     return -1;
64   }
65 
66   posix_spawnattr_destroy(&attributes);
67 
68   int status;
69   pid_t pid = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
70   return (pid == -1 ? -1 : status);
71 }
72