1
/* Copyright (C) 2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include <ndb_global.h>
20
#include "CpcClient.hpp"
22
#define CPC_CMD(name, value, desc) \
26
ParserRow_t::String, \
27
ParserRow_t::Optional, \
28
ParserRow_t::IgnoreMinMax, \
34
#define CPC_ARG(name, type, opt, desc) \
40
ParserRow_t::IgnoreMinMax, \
50
ParserRow_t::Optional, \
51
ParserRow_t::IgnoreMinMax, \
56
#ifdef DEBUG_PRINT_PROPERTIES
57
static void printprop(const Properties &p) {
58
Properties::Iterator iter(&p);
60
while((name = iter.next()) != NULL) {
65
p.getTypeOf(name, &t);
67
case PropertiesType_Uint32:
69
ndbout << name << " (Uint32): " << val_i << endl;
71
case PropertiesType_char:
73
ndbout << name << " (string): " << val_s << endl;
76
ndbout << "Unknown type " << t << endl;
84
SimpleCpcClient::cmd_stop(char *arg) {
86
Vector<Process> proc_list;
88
list_processes(proc_list, p);
91
for(size_t i = 0; i < proc_list.size(); i++) {
92
if(strcmp(proc_list[i].m_name.c_str(), arg) == 0) {
95
stop_process(proc_list[i].m_id, reply);
98
reply.get("status", &status);
101
reply.get("errormessage", msg);
102
ndbout << "Stop failed: " << msg << endl;
108
ndbout << "No such process" << endl;
112
SimpleCpcClient::stop_process(Uint32 id, Properties& reply){
113
const ParserRow_t stop_reply[] = {
114
CPC_CMD("stop process", NULL, ""),
115
CPC_ARG("status", Int, Mandatory, ""),
116
CPC_ARG("id", Int, Optional, ""),
117
CPC_ARG("errormessage", String, Optional, ""),
125
const Properties* ret = cpc_call("stop process", args, stop_reply);
127
reply.put("status", (Uint32)0);
128
reply.put("errormessage", "unknown error");
133
ret->get("status", &status);
134
reply.put("status", status);
137
ret->get("errormessage", msg);
138
reply.put("errormessage", msg.c_str());
145
SimpleCpcClient::cmd_start(char *arg) {
147
Vector<Process> proc_list;
148
list_processes(proc_list, p);
149
bool startped = false;
151
for(size_t i = 0; i < proc_list.size(); i++) {
152
if(strcmp(proc_list[i].m_name.c_str(), arg) == 0) {
156
start_process(proc_list[i].m_id, reply);
159
reply.get("status", &status);
162
reply.get("errormessage", msg);
163
ndbout << "Start failed: " << msg << endl;
169
ndbout << "No such process" << endl;
173
SimpleCpcClient::start_process(Uint32 id, Properties& reply){
174
const ParserRow_t start_reply[] = {
175
CPC_CMD("start process", NULL, ""),
176
CPC_ARG("status", Int, Mandatory, ""),
177
CPC_ARG("id", Int, Optional, ""),
178
CPC_ARG("errormessage", String, Optional, ""),
186
const Properties* ret = cpc_call("start process", args, start_reply);
188
reply.put("status", (Uint32)0);
189
reply.put("errormessage", "unknown error");
194
ret->get("status", &status);
195
reply.put("status", status);
198
ret->get("errormessage", msg);
199
reply.put("errormessage", msg.c_str());
206
SimpleCpcClient::undefine_process(Uint32 id, Properties& reply){
207
const ParserRow_t stop_reply[] = {
208
CPC_CMD("undefine process", NULL, ""),
209
CPC_ARG("status", Int, Mandatory, ""),
210
CPC_ARG("id", Int, Optional, ""),
211
CPC_ARG("errormessage", String, Optional, ""),
219
const Properties* ret = cpc_call("undefine process", args, stop_reply);
221
reply.put("status", (Uint32)0);
222
reply.put("errormessage", "unknown error");
227
ret->get("status", &status);
228
reply.put("status", status);
231
ret->get("errormessage", msg);
232
reply.put("errormessage", msg.c_str());
239
printproc(SimpleCpcClient::Process & p) {
240
ndbout.println("Name: %s", p.m_name.c_str());
241
ndbout.println("Id: %d", p.m_id);
242
ndbout.println("Type: %s", p.m_type.c_str());
243
ndbout.println("Group: %s", p.m_group.c_str());
244
ndbout.println("Program path: %s", p.m_path.c_str());
245
ndbout.println("Arguments: %s", p.m_args.c_str());
246
ndbout.println("Environment: %s", p.m_env.c_str());
247
ndbout.println("Working directory: %s", p.m_cwd.c_str());
248
ndbout.println("Owner: %s", p.m_owner.c_str());
249
ndbout.println("Runas: %s", p.m_runas.c_str());
250
ndbout.println("Ulimit: %s", p.m_ulimit.c_str());
255
SimpleCpcClient::cmd_list(char *arg) {
257
Vector<Process> proc_list;
258
list_processes(proc_list, p);
260
for(size_t i = 0; i < proc_list.size(); i++) {
261
printproc(proc_list[i]);
266
convert(const Properties & src, SimpleCpcClient::Process & dst){
268
b &= src.get("id", (Uint32*)&dst.m_id);
269
b &= src.get("name", dst.m_name);
270
b &= src.get("type", dst.m_type);
271
b &= src.get("status", dst.m_status);
272
b &= src.get("owner", dst.m_owner);
273
b &= src.get("group", dst.m_group);
274
b &= src.get("path", dst.m_path);
275
b &= src.get("args", dst.m_args);
276
b &= src.get("env", dst.m_env);
277
b &= src.get("cwd", dst.m_cwd);
278
b &= src.get("runas", dst.m_runas);
280
b &= src.get("stdin", dst.m_stdin);
281
b &= src.get("stdout", dst.m_stdout);
282
b &= src.get("stderr", dst.m_stderr);
283
b &= src.get("ulimit", dst.m_ulimit);
284
b &= src.get("shutdown", dst.m_shutdown_options);
290
convert(const SimpleCpcClient::Process & src, Properties & dst ){
292
//b &= dst.put("id", (Uint32)src.m_id);
293
b &= dst.put("name", src.m_name.c_str());
294
b &= dst.put("type", src.m_type.c_str());
295
//b &= dst.put("status", src.m_status.c_str());
296
b &= dst.put("owner", src.m_owner.c_str());
297
b &= dst.put("group", src.m_group.c_str());
298
b &= dst.put("path", src.m_path.c_str());
299
b &= dst.put("args", src.m_args.c_str());
300
b &= dst.put("env", src.m_env.c_str());
301
b &= dst.put("cwd", src.m_cwd.c_str());
302
b &= dst.put("runas", src.m_runas.c_str());
304
b &= dst.put("stdin", src.m_stdin.c_str());
305
b &= dst.put("stdout", src.m_stdout.c_str());
306
b &= dst.put("stderr", src.m_stderr.c_str());
307
b &= dst.put("ulimit", src.m_ulimit.c_str());
308
b &= dst.put("shutdown", src.m_shutdown_options.c_str());
314
SimpleCpcClient::define_process(Process & p, Properties& reply){
315
const ParserRow_t define_reply[] = {
316
CPC_CMD("define process", NULL, ""),
317
CPC_ARG("status", Int, Mandatory, ""),
318
CPC_ARG("id", Int, Optional, ""),
319
CPC_ARG("errormessage", String, Optional, ""),
327
const Properties* ret = cpc_call("define process", args, define_reply);
329
reply.put("status", (Uint32)0);
330
reply.put("errormessage", "unknown error");
335
ret->get("status", &status);
336
reply.put("status", status);
339
ret->get("errormessage", msg);
340
reply.put("errormessage", msg.c_str());
344
if(!ret->get("id", &id)){
354
SimpleCpcClient::list_processes(Vector<Process> &procs, Properties& reply) {
355
int start, end, entry;
356
const ParserRow_t list_reply[] = {
357
CPC_CMD("start processes", &start, ""),
358
CPC_CMD("end processes", &end, ""),
360
CPC_CMD("process", &entry, ""),
361
CPC_ARG("id", Int, Mandatory, "Id of process."),
362
CPC_ARG("name", String, Mandatory, "Name of process"),
363
CPC_ARG("group", String, Mandatory, "Group of process"),
364
CPC_ARG("env", String, Mandatory, "Environment variables for process"),
365
CPC_ARG("path", String, Mandatory, "Path to binary"),
366
CPC_ARG("args", String, Mandatory, "Arguments to process"),
367
CPC_ARG("type", String, Mandatory, "Type of process"),
368
CPC_ARG("cwd", String, Mandatory, "Working directory of process"),
369
CPC_ARG("owner", String, Mandatory, "Owner of process"),
370
CPC_ARG("status",String, Mandatory, "Status of process"),
371
CPC_ARG("runas", String, Mandatory, "Run as user"),
372
CPC_ARG("stdin", String, Mandatory, "Redirect stdin"),
373
CPC_ARG("stdout",String, Mandatory, "Redirect stdout"),
374
CPC_ARG("stderr",String, Mandatory, "Redirect stderr"),
375
CPC_ARG("ulimit",String, Mandatory, "ulimit"),
376
CPC_ARG("shutdown",String, Mandatory, "shutdown"),
383
const Properties args;
385
cpc_send("list processes", args);
389
const Properties *proc;
391
cpc_recv(list_reply, &proc, &p);
411
ndbout_c("internal error: %d", __LINE__);
419
SimpleCpcClient::cmd_help(char *arg) {
421
<< "HELP Print help text" << endl
422
<< "LIST List processes" << endl
423
<< "START Start process" << endl
424
<< "STOP Stop process" << endl;
427
SimpleCpcClient::SimpleCpcClient(const char *_host, int _port) {
428
host = strdup(_host);
433
SimpleCpcClient::~SimpleCpcClient() {
448
SimpleCpcClient::connect() {
449
struct sockaddr_in sa;
453
cpc_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
458
sa.sin_family = AF_INET;
459
hp = gethostbyname(host);
465
memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
466
sa.sin_port = htons(port);
467
if (::connect(cpc_sock, (struct sockaddr*) &sa, sizeof(sa)) < 0)
474
SimpleCpcClient::cpc_send(const char *cmd,
475
const Properties &args) {
476
SocketOutputStream cpc_out(cpc_sock);
478
cpc_out.println(cmd);
480
Properties::Iterator iter(&args);
482
while((name = iter.next()) != NULL) {
487
args.getTypeOf(name, &t);
489
case PropertiesType_Uint32:
490
args.get(name, &val_i);
491
cpc_out.println("%s: %d", name, val_i);
493
case PropertiesType_char:
494
args.get(name, val_s);
495
cpc_out.println("%s: %s", name, val_s.c_str());
498
/* Silently ignore */
508
* Receive a response from the CPCD. The argument reply will point
509
* to a Properties object describing the reply. Note that the caller
510
* is responsible for deleting the Properties object returned.
512
SimpleCpcClient::Parser_t::ParserStatus
513
SimpleCpcClient::cpc_recv(const ParserRow_t *syntax,
514
const Properties **reply,
516
SocketInputStream cpc_in(cpc_sock);
518
Parser_t::Context ctx;
519
ParserDummy session(cpc_sock);
520
Parser_t parser(syntax, cpc_in, true, true, true);
521
*reply = parser.parse(ctx, session);
522
if(user_value != NULL)
523
*user_value = ctx.m_currentCmd->user_value;
528
SimpleCpcClient::cpc_call(const char *cmd,
529
const Properties &args,
530
const ParserRow_t *reply_syntax) {
534
Parser_t::Context ctx;
535
ParserDummy session(cpc_sock);
536
Parser_t parser(reply_syntax, *cpc_in, true, true, true);
537
const Properties *ret = parser.parse(ctx, session);
540
const Properties *ret;
541
cpc_recv(reply_syntax, &ret);
546
SimpleCpcClient::ParserDummy::ParserDummy(NDB_SOCKET_TYPE sock)
547
: SocketServer::Session(sock) {
550
template class Vector<SimpleCpcClient::Process>;
551
template class Vector<ParserRow<SimpleCpcClient::ParserDummy> const*>;