00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "../../sr_module.h"
00033 #include "../../cfg/cfg.h"
00034 #include "../../cfg/cfg_ctx.h"
00035 #include "../../rpc.h"
00036
00037 static cfg_ctx_t *ctx = NULL;
00038
00039 MODULE_VERSION
00040
00041
00042 static int mod_init(void)
00043 {
00044 if (cfg_register_ctx(&ctx, NULL)) {
00045 LOG(L_ERR, "cfg_rpc: failed to register cfg context\n");
00046 return -1;
00047 }
00048
00049 return 0;
00050 }
00051
00052
00053
00054
00055
00056
00057 static int get_group_id(str *group, unsigned int **group_id)
00058 {
00059 static unsigned int id;
00060 str s;
00061
00062 if (!group->s || (group->s[group->len-1] != ']')) {
00063 *group_id = NULL;
00064 return 0;
00065 }
00066
00067 s.s = group->s + group->len - 2;
00068 s.len = 0;
00069 while ((s.s > group->s) && (*s.s != '[')) {
00070 s.s--;
00071 s.len++;
00072 }
00073 if (s.s == group->s)
00074 return -1;
00075 group->len = s.s - group->s;
00076 s.s++;
00077 if (!group->len || !s.len)
00078 return -1;
00079 if (str2int(&s, &id))
00080 return -1;
00081
00082 *group_id = &id;
00083 return 0;
00084 }
00085
00086 static const char* rpc_set_now_doc[2] = {
00087 "Set the value of a configuration variable and commit the change immediately",
00088 0
00089 };
00090
00091 static void rpc_set_now_int(rpc_t* rpc, void* c)
00092 {
00093 str group, var;
00094 int i;
00095 unsigned int *group_id;
00096
00097 if (rpc->scan(c, "SSd", &group, &var, &i) < 3)
00098 return;
00099
00100 if (get_group_id(&group, &group_id)) {
00101 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00102 return;
00103 }
00104
00105 if (cfg_set_now_int(ctx, &group, group_id, &var, i)) {
00106 rpc->fault(c, 400, "Failed to set the variable");
00107 return;
00108 }
00109 }
00110
00111 static void rpc_set_now_string(rpc_t* rpc, void* c)
00112 {
00113 str group, var;
00114 char *ch;
00115 unsigned int *group_id;
00116
00117 if (rpc->scan(c, "SSs", &group, &var, &ch) < 3)
00118 return;
00119
00120 if (get_group_id(&group, &group_id)) {
00121 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00122 return;
00123 }
00124
00125 if (cfg_set_now_string(ctx, &group, group_id, &var, ch)) {
00126 rpc->fault(c, 400, "Failed to set the variable");
00127 return;
00128 }
00129 }
00130
00131 static void rpc_set(rpc_t* rpc, void* c)
00132 {
00133 str group, var;
00134 int i, err;
00135 char *ch;
00136 unsigned int *group_id;
00137
00138 if (rpc->scan(c, "SS", &group, &var) < 2)
00139 return;
00140
00141 if (get_group_id(&group, &group_id)) {
00142 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00143 return;
00144 }
00145
00146 if (rpc->scan(c, "d", &i) == 1)
00147 err = cfg_set_now_int(ctx, &group, group_id, &var, i);
00148 else if (rpc->scan(c, "s", &ch) == 1)
00149 err = cfg_set_now_string(ctx, &group, group_id, &var, ch);
00150 else
00151 return;
00152
00153 if (err) {
00154 rpc->fault(c, 400, "Failed to set the variable");
00155 return;
00156 }
00157 }
00158
00159 static const char* rpc_del_now_doc[2] = {
00160 "Delete the value of a configuration variable from a group instance and commit the change immediately",
00161 0
00162 };
00163
00164 static void rpc_del(rpc_t* rpc, void* c)
00165 {
00166 str group, var;
00167 unsigned int *group_id;
00168
00169 if (rpc->scan(c, "SS", &group, &var) < 2)
00170 return;
00171
00172 if (get_group_id(&group, &group_id) || !group_id) {
00173 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00174 return;
00175 }
00176
00177 if (cfg_del_now(ctx, &group, group_id, &var)) {
00178 rpc->fault(c, 400, "Failed to delete the value");
00179 return;
00180 }
00181 }
00182
00183 static const char* rpc_set_delayed_doc[2] = {
00184 "Prepare the change of a configuration variable, but does not commit the new value yet",
00185 0
00186 };
00187
00188 static void rpc_set_delayed_int(rpc_t* rpc, void* c)
00189 {
00190 str group, var;
00191 int i;
00192 unsigned int *group_id;
00193
00194 if (rpc->scan(c, "SSd", &group, &var, &i) < 3)
00195 return;
00196
00197 if (get_group_id(&group, &group_id)) {
00198 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00199 return;
00200 }
00201
00202 if (cfg_set_delayed_int(ctx, &group, group_id, &var, i)) {
00203 rpc->fault(c, 400, "Failed to set the variable");
00204 return;
00205 }
00206 }
00207
00208 static void rpc_set_delayed_string(rpc_t* rpc, void* c)
00209 {
00210 str group, var;
00211 char *ch;
00212 unsigned int *group_id;
00213
00214 if (rpc->scan(c, "SSs", &group, &var, &ch) < 3)
00215 return;
00216
00217 if (get_group_id(&group, &group_id)) {
00218 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00219 return;
00220 }
00221
00222 if (cfg_set_delayed_string(ctx, &group, group_id, &var, ch)) {
00223 rpc->fault(c, 400, "Failed to set the variable");
00224 return;
00225 }
00226 }
00227
00228 static void rpc_set_delayed(rpc_t* rpc, void* c)
00229 {
00230 str group, var;
00231 int i, err;
00232 char *ch;
00233 unsigned int *group_id;
00234
00235 if (rpc->scan(c, "SS", &group, &var) < 2)
00236 return;
00237
00238 if (get_group_id(&group, &group_id)) {
00239 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00240 return;
00241 }
00242
00243 if (rpc->scan(c, "d", &i) == 1)
00244 err = cfg_set_delayed_int(ctx, &group, group_id, &var, i);
00245 else if (rpc->scan(c, "s", &ch) == 1)
00246 err = cfg_set_delayed_string(ctx, &group, group_id, &var, ch);
00247 else
00248 return;
00249
00250 if (err) {
00251 rpc->fault(c, 400, "Failed to set the variable");
00252 return;
00253 }
00254 }
00255
00256 static const char* rpc_del_delayed_doc[2] = {
00257 "Prepare the deletion of the value of a configuration variable from a group instance, but does not commit the change yet",
00258 0
00259 };
00260
00261 static void rpc_del_delayed(rpc_t* rpc, void* c)
00262 {
00263 str group, var;
00264 unsigned int *group_id;
00265
00266 if (rpc->scan(c, "SS", &group, &var) < 2)
00267 return;
00268
00269 if (get_group_id(&group, &group_id) || !group_id) {
00270 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00271 return;
00272 }
00273
00274 if (cfg_del_delayed(ctx, &group, group_id, &var)) {
00275 rpc->fault(c, 400, "Failed to delete the value");
00276 return;
00277 }
00278 }
00279
00280 static const char* rpc_commit_doc[2] = {
00281 "Commit the previously prepared configuration changes",
00282 0
00283 };
00284
00285 static void rpc_commit(rpc_t* rpc, void* c)
00286 {
00287 if (cfg_commit(ctx)) {
00288 rpc->fault(c, 400, "Failed to commit the changes");
00289 return;
00290 }
00291 }
00292
00293 static const char* rpc_rollback_doc[2] = {
00294 "Drop the prepared configuration changes",
00295 0
00296 };
00297
00298 static void rpc_rollback(rpc_t* rpc, void* c)
00299 {
00300 if (cfg_rollback(ctx)) {
00301 rpc->fault(c, 400, "Failed to drop the changes");
00302 return;
00303 }
00304 }
00305
00306 static const char* rpc_get_doc[2] = {
00307 "Get the value of a configuration variable",
00308 0
00309 };
00310
00311 static void rpc_get(rpc_t* rpc, void* c)
00312 {
00313 str group, var;
00314 void *val;
00315 unsigned int val_type;
00316 int ret;
00317 unsigned int *group_id;
00318
00319 if (rpc->scan(c, "SS", &group, &var) < 2)
00320 return;
00321
00322 if (get_group_id(&group, &group_id)) {
00323 rpc->fault(c, 400, "Wrong group syntax. Use either \"group\", or \"group[id]\"");
00324 return;
00325 }
00326
00327 ret = cfg_get_by_name(ctx, &group, group_id, &var,
00328 &val, &val_type);
00329 if (ret < 0) {
00330 rpc->fault(c, 400, "Failed to get the variable");
00331 return;
00332
00333 } else if (ret > 0) {
00334 rpc->fault(c, 400, "Variable exists, but it is not readable via RPC interface");
00335 return;
00336 }
00337
00338 switch (val_type) {
00339 case CFG_VAR_INT:
00340 rpc->add(c, "d", (int)(long)val);
00341 break;
00342
00343 case CFG_VAR_STRING:
00344 rpc->add(c, "s", (char *)val);
00345 break;
00346
00347 case CFG_VAR_STR:
00348 rpc->add(c, "S", (str *)val);
00349 break;
00350
00351 case CFG_VAR_POINTER:
00352 rpc->printf(c, "%p", val);
00353 break;
00354
00355 }
00356
00357 }
00358
00359 static const char* rpc_help_doc[2] = {
00360 "Print the description of a configuration variable",
00361 0
00362 };
00363
00364 static void rpc_help(rpc_t* rpc, void* c)
00365 {
00366 str group, var;
00367 char *ch;
00368 unsigned int input_type;
00369
00370 if (rpc->scan(c, "SS", &group, &var) < 2)
00371 return;
00372
00373 if (cfg_help(ctx, &group, &var,
00374 &ch, &input_type)
00375 ) {
00376 rpc->fault(c, 400, "Failed to get the variable description");
00377 return;
00378 }
00379 rpc->add(c, "s", ch);
00380
00381 switch (input_type) {
00382 case CFG_INPUT_INT:
00383 rpc->printf(c, "(parameter type is integer)");
00384 break;
00385
00386 case CFG_INPUT_STRING:
00387 case CFG_INPUT_STR:
00388 rpc->printf(c, "(parameter type is string)");
00389 break;
00390 }
00391 }
00392
00393 static const char* rpc_list_doc[2] = {
00394 "List the configuration variables",
00395 0
00396 };
00397
00398 static void rpc_list(rpc_t* rpc, void* c)
00399 {
00400 void *h;
00401 str gname;
00402 cfg_def_t *def;
00403 int i;
00404 str group;
00405
00406 if (rpc->scan(c, "*S", &group) < 1) {
00407 group.s = NULL;
00408 group.len = 0;
00409 }
00410
00411 cfg_get_group_init(&h);
00412 while(cfg_get_group_next(&h, &gname, &def))
00413 if (!group.len
00414 || ((gname.len == group.len)
00415 && (memcmp(gname.s, group.s, group.len) == 0))
00416 )
00417 for (i=0; def[i].name; i++)
00418 rpc->printf(c, "%.*s: %s", gname.len, gname.s, def[i].name);
00419 }
00420
00421 static const char* rpc_diff_doc[2] = {
00422 "List the pending configuration changes that have not been committed yet",
00423 0
00424 };
00425
00426 static void rpc_diff(rpc_t* rpc, void* c)
00427 {
00428 void *h;
00429 str gname, vname;
00430 unsigned int *gid;
00431 void *old_val, *new_val;
00432 unsigned int val_type;
00433 void *rpc_handle;
00434 int err;
00435
00436
00437 if (cfg_diff_init(ctx, &h)) {
00438 rpc->fault(c, 400, "Failed to get the changes");
00439 return;
00440 }
00441 while((err = cfg_diff_next(&h,
00442 &gname, &gid, &vname,
00443 &old_val, &new_val,
00444 &val_type)) > 0
00445 ) {
00446 rpc->add(c, "{", &rpc_handle);
00447 if (gid)
00448 rpc->struct_add(rpc_handle, "SdS",
00449 "group name", &gname,
00450 "group id", *gid,
00451 "variable name", &vname);
00452 else
00453 rpc->struct_add(rpc_handle, "SS",
00454 "group name", &gname,
00455 "variable name", &vname);
00456
00457 switch (val_type) {
00458 case CFG_VAR_INT:
00459 rpc->struct_add(rpc_handle, "dd",
00460 "old value", (int)(long)old_val,
00461 "new value", (int)(long)new_val);
00462 break;
00463
00464 case CFG_VAR_STRING:
00465 rpc->struct_add(rpc_handle, "ss",
00466 "old value", (char *)old_val,
00467 "new value", (char *)new_val);
00468 break;
00469
00470 case CFG_VAR_STR:
00471 rpc->struct_add(rpc_handle, "SS",
00472 "old value", (str *)old_val,
00473 "new value", (str *)new_val);
00474 break;
00475
00476 case CFG_VAR_POINTER:
00477
00478 break;
00479
00480 }
00481 }
00482 cfg_diff_release(ctx);
00483 if (err)
00484 rpc->fault(c, 400, "Failed to get the changes");
00485 }
00486
00487 static const char* rpc_add_group_inst_doc[2] = {
00488 "Add a new instance to an existing configuration group",
00489 0
00490 };
00491
00492 static void rpc_add_group_inst(rpc_t* rpc, void* c)
00493 {
00494 str group;
00495 unsigned int *group_id;
00496
00497 if (rpc->scan(c, "S", &group) < 1)
00498 return;
00499
00500 if (get_group_id(&group, &group_id) || !group_id) {
00501 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00502 return;
00503 }
00504
00505 if (cfg_add_group_inst(ctx, &group, *group_id)) {
00506 rpc->fault(c, 400, "Failed to add the group instance");
00507 return;
00508 }
00509 }
00510
00511 static const char* rpc_del_group_inst_doc[2] = {
00512 "Delte an instance of a configuration group",
00513 0
00514 };
00515
00516 static void rpc_del_group_inst(rpc_t* rpc, void* c)
00517 {
00518 str group;
00519 unsigned int *group_id;
00520
00521 if (rpc->scan(c, "S", &group) < 1)
00522 return;
00523
00524 if (get_group_id(&group, &group_id) || !group_id) {
00525 rpc->fault(c, 400, "Wrong group syntax. Use \"group[id]\"");
00526 return;
00527 }
00528
00529 if (cfg_del_group_inst(ctx, &group, *group_id)) {
00530 rpc->fault(c, 400, "Failed to delete the group instance");
00531 return;
00532 }
00533 }
00534
00535 static rpc_export_t rpc_calls[] = {
00536 {"cfg.set", rpc_set, rpc_set_now_doc, 0},
00537 {"cfg.set_now_int", rpc_set_now_int, rpc_set_now_doc, 0},
00538 {"cfg.seti", rpc_set_now_int, rpc_set_now_doc, 0},
00539 {"cfg.set_now_string", rpc_set_now_string, rpc_set_now_doc, 0},
00540 {"cfg.sets", rpc_set_now_string, rpc_set_now_doc, 0},
00541 {"cfg.del", rpc_del, rpc_del_now_doc, 0},
00542 {"cfg.set_delayed", rpc_set_delayed, rpc_set_delayed_doc, 0},
00543 {"cfg.set_delayed_int", rpc_set_delayed_int, rpc_set_delayed_doc, 0},
00544 {"cfg.set_delayed_string", rpc_set_delayed_string, rpc_set_delayed_doc, 0},
00545 {"cfg.del_delayed", rpc_del_delayed, rpc_del_delayed_doc, 0},
00546 {"cfg.commit", rpc_commit, rpc_commit_doc, 0},
00547 {"cfg.rollback", rpc_rollback, rpc_rollback_doc, 0},
00548 {"cfg.get", rpc_get, rpc_get_doc, 0},
00549 {"cfg.help", rpc_help, rpc_help_doc, 0},
00550 {"cfg.list", rpc_list, rpc_list_doc, 0},
00551 {"cfg.diff", rpc_diff, rpc_diff_doc, 0},
00552 {"cfg.add_group_inst", rpc_add_group_inst, rpc_add_group_inst_doc, 0},
00553 {"cfg.del_group_inst", rpc_del_group_inst, rpc_del_group_inst_doc, 0},
00554 {0, 0, 0, 0}
00555 };
00556
00557
00558 struct module_exports exports = {
00559 "cfg_rpc",
00560 0,
00561 rpc_calls,
00562 0,
00563 mod_init,
00564 0,
00565 0,
00566 0,
00567 0
00568 };