summaryrefslogtreecommitdiffstats
path: root/src/lib/asiolink/process_spawn.h
blob: 7d6e6623011bad72b5f2393d9ab58883163ef449 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef PROCESS_SPAWN_H
#define PROCESS_SPAWN_H

#include <asiolink/io_service.h>
#include <exceptions/exceptions.h>
#include <boost/noncopyable.hpp>
#include <string>
#include <sys/types.h>
#include <vector>
#include <boost/shared_ptr.hpp>

namespace isc {
namespace asiolink {

/// @brief Exception thrown when error occurs during spawning a process.
class ProcessSpawnError : public Exception {
public:
    ProcessSpawnError(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

/// @brief Forward declaration to the implementation of the @c ProcessSpawn
/// class.
class ProcessSpawnImpl;

/// @brief Pointer to a ProcessSpawnImpl class.
typedef boost::shared_ptr<ProcessSpawnImpl> ProcessSpawnImplPtr;

/// @brief Type of the container holding arguments of the executable
/// being run as a background process.
typedef std::vector<std::string> ProcessArgs;

/// @brief Type of the container holding environment variables of the executable
/// being run as a background process.
typedef std::vector<std::string> ProcessEnvVars;

/// @brief Utility class for spawning new processes.
///
/// This class is used to spawn new process by Kea. It forks the current
/// process and then uses the @c execve function to execute the specified
/// binary with parameters. The @c ProcessSpawn installs the handler for
/// the SIGCHLD signal, which is executed when the child process ends.
/// The handler checks the exit code returned by the process and records
/// it. The exit code can be retrieved by the caller using the
/// @c ProcessSpawn::getExitStatus method.
///
/// This class is made noncopyable so that we don't have attempts
/// to make multiple copies of an object.  This avoid problems
/// with multiple copies of objects for a single global resource
/// such as the SIGCHLD signal handler. In addition making it
/// noncopyable keeps the static check code from flagging the
/// lack of a copy constructor as an issue.
///
/// @note The ProcessSpawn uses full path for the program to execute.
class ProcessSpawn : boost::noncopyable {
public:

    /// @brief Constructor.
    ///
    /// @param io_service The IOService which handles signal handlers.
    /// @param executable A full path to the program to be executed.
    /// @param args Arguments for the program to be executed.
    /// @param vars Environment variables for the program to be executed.
    /// @param inherit_env whether the spawned process will inherit the
    ///        environment before adding 'vars' on top.
    ProcessSpawn(isc::asiolink::IOServicePtr io_service,
                 const std::string& executable,
                 const ProcessArgs& args = ProcessArgs(),
                 const ProcessEnvVars& vars = ProcessEnvVars(),
                 const bool inherit_env = false);

    /// @brief Destructor.
    ~ProcessSpawn() = default;

    /// @brief Returns full command line, including arguments, for the process.
    std::string getCommandLine() const;

    /// @brief Spawn the new process.
    ///
    /// This method forks the current process and executes the specified
    /// binary with arguments within the child process.
    ///
    /// The child process will return EXIT_FAILURE if the method was unable
    /// to start the executable, e.g. as a result of insufficient permissions
    /// or when the executable does not exist. If the process ends successfully
    /// the EXIT_SUCCESS is returned.
    ///
    /// @param dismiss The flag which indicated if the process status can be
    /// disregarded.
    /// @throw ProcessSpawnError if forking a current process failed.
    pid_t spawn(bool dismiss = false);

    /// @brief Checks if the process is still running.
    ///
    /// Note that only a negative (false) result is reliable as the child
    /// process can exit between the time its state is checked and this
    /// function returns.
    ///
    /// @param pid ID of the child processes for which state should be checked.
    ///
    /// @return true if the child process is running, false otherwise.
    bool isRunning(const pid_t pid) const;

    /// @brief Checks if any of the spawned processes is still running.
    ///
    /// @return true if at least one child process is still running.
    bool isAnyRunning() const;

    /// @brief Returns exit status of the process.
    ///
    /// If the process is still running, the previous status is returned
    /// or 0, if the process is being ran for the first time.
    ///
    /// @note @c ProcessSpawn::isRunning should be called and have returned
    /// false before using @c ProcessSpawn::getExitStatus.
    ///
    /// @param pid ID of the child process for which exit status should be
    /// returned.
    ///
    /// @return Exit code of the process.
    int getExitStatus(const pid_t pid) const;

    /// @brief Removes the status of the process with a specified PID.
    ///
    /// This method removes the status of the process with a specified PID.
    /// If the process is still running, the status is not removed and the
    /// exception is thrown.
    ///
    /// Note @c ProcessSpawn::isRunning must be called and have returned
    /// false before using clearState(). And of course
    /// @c ProcessSpawn::getExitStatus should be called first, if there is
    /// some interest in the status.
    ///
    /// @param pid A process pid.
    void clearState(const pid_t pid);

private:

    /// @brief A smart pointer to the implementation of this class.
    ProcessSpawnImplPtr impl_;
};

} // namespace asiolink
} // namespace isc

#endif // PROCESS_SPAWN_H