1 /*
2 Copyright (C) 2003-2007 MySQL AB, 2009, 2010 Sun Microsystems, Inc.
3 All rights reserved. Use is subject to license terms.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 #ifndef CPCD_HPP
27 #define CPCD_HPP
28
29 #include <Vector.hpp>
30 #include <Properties.hpp>
31 #include <NdbOut.hpp>
32 #include <NdbThread.h>
33 #include <NdbCondition.h>
34 #include <BaseString.hpp>
35
36 #ifdef _WIN32
37 typedef DWORD pid_t;
38 #endif
39 const pid_t bad_pid = -1;
40
is_bad_pid(pid_t pid)41 inline bool is_bad_pid(pid_t pid)
42 {
43 #ifdef _WIN32
44 return pid == bad_pid;
45 #else
46 return pid <= 1;
47 #endif
48 }
49
50 #define CPCD_DEFAULT_PROC_FILE "ndb_cpcd.conf"
51 #define CPCD_DEFAULT_TCP_PORT 1234
52 #define CPCD_DEFAULT_POLLING_INTERVAL 5 /* seconds */
53 #ifndef _WIN32
54 #define CPCD_DEFAULT_WORK_DIR "/var/run/ndb_cpcd"
55 #define CPCD_DEFAULT_CONFIG_FILE "/etc/ndb_cpcd.conf"
56
57 #else
58 #define CPCD_DEFAULT_WORK_DIR "c:\\ndb_cpcd"
59 #define CPCD_DEFAULT_CONFIG_FILE "c:\\ndb_cpcd\\ndb_cpcd.conf"
60 #endif
61 enum ProcessStatus {
62 STOPPED = 0,
63 STARTING = 1,
64 RUNNING = 2,
65 STOPPING = 3
66 };
67
68 enum ProcessType {
69 PERMANENT = 0,
70 TEMPORARY = 1
71 };
72
73 /**
74 * @brief Error codes for CPCD requests
75 */
76 enum RequestStatusCode {
77 OK = 0, ///< Everything OK
78 Error = 1, ///< Generic error
79 AlreadyExists = 2, ///< Entry already exists in list
80 NotExists = 3, ///< Entry does not exist in list
81 AlreadyStopped = 4
82 };
83
84 /**
85 * @class CPCD
86 * @brief Manages processes, letting them be controlled with a TCP connection.
87 *
88 * The class implementing the Cluster Process Control Daemon
89 */
90 class CPCD {
91 public:
92 /** @brief Describes the status of a client request */
93 class RequestStatus {
94 public:
95 /** @brief Constructs an empty RequestStatus */
RequestStatus()96 RequestStatus() { m_status = OK; m_errorstring[0] = '\0'; };
97
98 /** @brief Sets an errorcode and a printable message */
99 void err(enum RequestStatusCode, const char *);
100
101 /** @brief Returns the error message */
getErrMsg()102 char *getErrMsg() { return m_errorstring; };
103
104 /** @brief Returns the error code */
getStatus()105 enum RequestStatusCode getStatus() { return m_status; };
106 private:
107 enum RequestStatusCode m_status;
108 char m_errorstring[256];
109 };
110 /**
111 * @brief Manages a process
112 */
113 class Process {
114 pid_t m_pid;
115 #ifdef _WIN32
116 HANDLE m_job;
117 #endif
118 public:
119 /**
120 * @brief Constructs and empty Process
121 */
122 Process(const Properties & props, class CPCD *cpcd);
123 /**
124 * @brief Monitors the process
125 *
126 * The process is started or stopped as needed.
127 */
128 void monitor();
129
130 /**
131 * @brief Checks if the process is running or not
132 *
133 * @return
134 * - true if the process is running,
135 * - false if the process is not running
136 */
137 bool isRunning();
138
139 /** @brief Starts the process */
140 int start();
141
142 /** @brief Stops the process */
143 void stop();
144
145 /**
146 * @brief Reads the pid from stable storage
147 *
148 * @return The pid number
149 */
150 int readPid();
151
152 /**
153 * @brief Writes the pid from stable storage
154 *
155 * @return
156 * - 0 if successful
157 - -1 and sets errno if an error occured
158 */
159 int writePid(int pid);
160
161 /**
162 * @brief Prints a textual description of the process on a file
163 */
164 void print(FILE *);
165
166 /** Id number of the Process.
167 *
168 * @note This is not the same as a pid. This number is used in the
169 * protocol, and will not be changed if a processes is restarted.
170 */
171 int m_id;
172
173 /** @brief The name shown to the user */
174 BaseString m_name;
175
176 /** @brief Used to group a number of processes */
177 BaseString m_group;
178
179 /** @brief Environment variables
180 *
181 * Environmentvariables to add for the process.
182 *
183 * @note
184 * - The environment cpcd started with is preserved
185 * - There is no way to delete variables
186 */
187 BaseString m_env;
188
189 /** @brief Path to the binary to run */
190 BaseString m_path;
191
192 /** @brief Arguments to the process.
193 *
194 * @note
195 * - This includes argv[0].
196 * - If no argv[0] is given, argv[0] will be set to m_path.
197 */
198 BaseString m_args;
199
200 /**
201 * @brief Type of process
202 *
203 * Either set to "interactive" or "permanent".
204 */
205 BaseString m_type;
206 ProcessType m_processType;
207
208 /**
209 * @brief Working directory
210 *
211 * Working directory the process will start in.
212 */
213 BaseString m_cwd;
214
215 /**
216 * @brief Owner of the process.
217 *
218 * @note This will not affect the process' uid or gid;
219 * it is only used for managemental purposes.
220 * @see m_runas
221 */
222 BaseString m_owner;
223
224 /**
225 * @bried Run as
226 * @note This affects uid
227 * @see m_owner
228 */
229 BaseString m_runas;
230
231 /**
232 * @brief redirection for stdin
233 */
234 BaseString m_stdin;
235
236 /**
237 * @brief redirection for stdout
238 */
239 BaseString m_stdout;
240
241 /**
242 * @brief redirection for stderr
243 */
244 BaseString m_stderr;
245
246 /** @brief Status of the process */
247 enum ProcessStatus m_status;
248
249 /**
250 * @brief ulimits for process
251 * @desc Format c:unlimited d:0 ...
252 */
253 BaseString m_ulimit;
254
255 /**
256 * @brief shutdown options
257 */
258 BaseString m_shutdown_options;
259
260 private:
261 class CPCD *m_cpcd;
262 void do_exec();
263 };
264
265 /**
266 * @brief Starts and stops processes as needed
267 *
268 * At a specified interval (default 5 seconds) calls the monitor function
269 * of all the processes in the CPCDs list, causing the to start or
270 * stop, depending on the configuration.
271 */
272 class Monitor {
273 public:
274 /** Creates a new CPCD::Monitor object, connected to the specified
275 * CPCD.
276 * A new thread will be created, which will poll the processes of
277 * the CPCD at the specifed interval.
278 */
279 Monitor(CPCD *cpcd, int poll = CPCD_DEFAULT_POLLING_INTERVAL);
280
281 /** Stops the monitor, but does not stop the processes */
282 ~Monitor();
283
284 /** Runs the monitor thread. */
285 void run();
286
287 /** Signals configuration changes to the monitor thread, causing it to
288 * do the check without waiting for the timeout */
289 void signal();
290 private:
291 class CPCD *m_cpcd;
292 struct NdbThread *m_monitorThread;
293 bool m_monitorThreadQuitFlag;
294 struct NdbCondition *m_changeCondition;
295 NdbMutex *m_changeMutex;
296 int m_pollingInterval; /* seconds */
297 };
298
299 /** @brief Constructs a CPCD object */
300 CPCD();
301
302 /**
303 * @brief Destroys a CPCD object,
304 * but does not stop the processes it manages
305 */
306 ~CPCD();
307
308 /** Adds a Process to the CPCDs list of managed Processes.
309 *
310 * @note The process will not be started until it is explicitly
311 * marked as running with CPCD::startProcess().
312 *
313 * @return
314 * - true if the addition was successful,
315 * - false if not
316 * - RequestStatus will be filled in with a suitable error
317 * if an error occured.
318 */
319 bool defineProcess(RequestStatus *rs, Process * arg);
320
321 /** Removes a Process from the CPCD.
322 *
323 * @note A Process that is running cannot be removed.
324 *
325 * @return
326 * - true if the removal was successful,
327 * - false if not
328 * - The RequestStatus will be filled in with a suitable error
329 * if an error occured.
330 */
331 bool undefineProcess(RequestStatus *rs, int id);
332
333 /** Marks a Process for starting.
334 *
335 * @note The fact that a process has started does not mean it will actually
336 * start properly. This command only makes sure the CPCD will
337 * try to start it.
338 *
339 * @return
340 * - true if the marking was successful
341 * - false if not
342 * - RequestStatus will be filled in with a suitable error
343 * if an error occured.
344 */
345 bool startProcess(RequestStatus *rs, int id);
346
347 /** Marks a Process for stopping.
348 *
349 * @return
350 * - true if the marking was successful
351 * - false if not
352 * - The RequestStatus will be filled in with a suitable error
353 * if an error occured.
354 */
355 bool stopProcess(RequestStatus *rs, int id);
356
357 /** Generates a list of processes, and sends them to the CPCD client */
358 bool listProcesses(RequestStatus *rs, MutexVector<const char *> &);
359
360 /** Set to true while the CPCD is reading the configuration file */
361 bool loadingProcessList;
362
363 /** Saves the list of Processes and their status to the configuration file.
364 * Called whenever the configuration is changed.
365 */
366 bool saveProcessList();
367
368 /** Loads the list of Processes and their status from the configuration
369 * file.
370 * @note This function should only be called when the CPCD is starting,
371 * calling it at other times will cause unspecified behaviour.
372 */
373 bool loadProcessList();
374
375 /** Returns the list of processes */
376 MutexVector<Process *> *getProcessList();
377
378 /** The list of processes. Should not be used directly */
379 MutexVector<Process *> m_processes;
380
381 private:
382 friend class Process;
383 bool notifyChanges();
384 int findUniqueId();
385 BaseString m_procfile;
386 Monitor *m_monitor;
387 };
388
389 #endif
390