| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244 |
- /*
- * Copyright (C) 2006 iptelorg GmbH
- *
- * This file is part of kamcmd, a free cli tool for Kamailio SIP server.
- *
- * kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the kamailio software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /*
- * send commands using binrpc
- *
- */
- #include <stdlib.h> /* exit, abort */
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- #include <ctype.h> /* isprint */
- #include <sys/socket.h>
- #include <sys/un.h> /* unix sock*/
- #include <netinet/in.h> /* udp sock */
- #include <sys/uio.h> /* writev */
- #include <netdb.h> /* gethostbyname */
- #include <fcntl.h>
- #include <time.h> /* time */
- #include <sys/time.h>
- #ifdef USE_READLINE
- #include <readline/readline.h>
- #include <readline/history.h>
- #define USE_CFG_VARS /* cfg group and vars completion */
- #define USE_COUNTERS /* counters/statistics completion */
- #endif
- #include "parse_listen_id.h"
- #include "license.h"
- #include "../../src/modules/ctl/ctl_defaults.h" /* default socket & port */
- #include "../../src/modules/ctl/binrpc.h"
- #include "../../src/modules/ctl/binrpc.c" /* ugly hack */
- #ifndef NAME
- #define NAME "kamcmd"
- #endif
- #ifndef VERSION
- #define VERSION "1.5"
- #endif
- #define IOVEC_CNT 20
- #define MAX_LINE_SIZE 16 * 1024 /* for non readline mode */
- #define MAX_REPLY_SIZE 128 * 1024
- #define MAX_BODY_SIZE 128 * 1024
- #define MAX_BINRPC_ARGS 256
- #ifndef UNIX_PATH_MAX
- #define UNIX_PATH_MAX 104
- #endif
- static char version[] = NAME " " VERSION;
- #ifdef VERSION_NODATE
- static char compiled[] = "";
- #else
- #ifdef VERSION_DATE
- static char compiled[] = VERSION_DATE;
- #else
- static char compiled[] = __TIME__ " " __DATE__;
- #endif
- #endif
- static char help_msg[] = "\
- Usage: " NAME " [options][-s address] [ cmd ]\n\
- Options:\n\
- -s address unix socket name or host name to send the commands on\n\
- -R name force reply socket name, for the unix datagram socket mode\n\
- -D dir create the reply socket in the directory <dir> if no reply \n\
- socket is forced (-R) and a unix datagram socket is selected\n\
- as the transport\n\
- -f format print the result using format. Format is a string containing\n\
- %v at the places where values read from the reply should be\n\
- substituted. To print '%v', escape it using '%': %%v.\n\
- -v Verbose \n\
- -V Version number\n\
- -h This help message\n\
- address:\n\
- [proto:]name[:port] where proto is one of tcp, udp, unixs or unixd\n\
- e.g.: tcp:localhost:2049 , unixs:/tmp/kamailio_ctl\n\
- cmd:\n\
- method [arg1 [arg2...]]\n\
- arg:\n\
- string or number; to force a number to be interpreted as string \n\
- prefix it by \"s:\", e.g. s:1\n\
- Examples:\n\
- " NAME " -s unixs:/tmp/" NAME "_ctl system.listMethods\n\
- " NAME " -f \"pid: %v desc: %v\\n\" -s udp:localhost:2047 core.ps \n\
- " NAME " ps # uses default ctl socket \n\
- " NAME " # enters interactive mode on the default socket \n\
- " NAME " -s tcp:localhost # interactive mode, default port \n\
- ";
- int verbose = 0;
- char *reply_socket = 0; /* unix datagram reply socket name */
- char *sock_dir = 0; /* same as above, but only the directory */
- char *unix_socket = 0;
- struct sockaddr_un mysun;
- int quit; /* used only in interactive mode */
- struct binrpc_val *rpc_array;
- int rpc_no = 0;
- #ifdef USE_CFG_VARS
- struct binrpc_val *cfg_vars_array;
- int cfg_vars_no;
- struct cfg_var_grp
- {
- struct cfg_var_grp *next;
- str grp_name; /**< group name */
- str *var_names; /**< str array, null terminated */
- int var_no;
- };
- struct cfg_var_grp *cfg_grp_lst; /** cfg groups list, allong with var names*/
- struct cfg_var_grp *crt_cfg_grp;
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- struct binrpc_val *cnt_grps_array; /* response array */
- int cnt_grps_no; /* number of response records */
- struct cnt_var_grp
- {
- struct cnt_var_grp *next;
- str grp_name;
- str *var_names; /**< str array (null terminated strings)*/
- int var_no;
- struct binrpc_val *cnt_vars_array; /* var_name will point here */
- int cnt_vars_no; /* cnt_vars_array size (no. of response records) */
- };
- struct cnt_var_grp *cnt_grp_lst; /* counters groups list, allong with vars */
- struct cnt_var_grp *crt_cnt_grp;
- #endif /* USE_COUNTERS */
- #define IOV_SET(vect, str) \
- do { \
- (vect).iov_base = (str); \
- (vect).iov_len = strlen((str)); \
- } while(0)
- #define INT2STR_MAX_LEN (19 + 1 + 1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
- /* returns a pointer to a static buffer containing l in asciiz & sets len */
- static inline char *int2str(unsigned int l, int *len)
- {
- static char r[INT2STR_MAX_LEN];
- int i;
- i = INT2STR_MAX_LEN - 2;
- r[INT2STR_MAX_LEN - 1] = 0; /* null terminate */
- do {
- r[i] = l % 10 + '0';
- i--;
- l /= 10;
- } while(l && (i >= 0));
- if(l && (i < 0)) {
- fprintf(stderr, "BUG: int2str: overflow\n");
- }
- if(len)
- *len = (INT2STR_MAX_LEN - 2) - i;
- return &r[i + 1];
- }
- static char *trim_ws(char *l)
- {
- char *ret;
- for(; *l && ((*l == ' ') || (*l == '\t') || (*l == '\n') || (*l == '\r'));
- l++)
- ;
- ret = l;
- if(*ret == 0)
- return ret;
- for(l = l + strlen(l) - 1;
- (l > ret)
- && ((*l == ' ') || (*l == '\t') || (*l == '\n') || (*l == '\r'));
- l--)
- ;
- *(l + 1) = 0;
- return ret;
- }
- int gen_cookie()
- {
- return rand();
- }
- struct binrpc_cmd
- {
- char *method;
- int argc;
- struct binrpc_val argv[MAX_BINRPC_ARGS];
- };
- struct cmd_alias
- {
- char *name;
- char *method;
- char *format; /* reply print format */
- };
- struct kamcmd_builtin
- {
- char *name;
- int (*f)(int, struct binrpc_cmd *);
- char *doc;
- };
- static int kamcmd_help(int s, struct binrpc_cmd *cmd);
- static int kamcmd_ver(int s, struct binrpc_cmd *cmd);
- static int kamcmd_quit(int s, struct binrpc_cmd *cmd);
- static int kamcmd_warranty(int s, struct binrpc_cmd *cmd);
- static struct cmd_alias cmd_aliases[] = {{"ps", "core.ps", "%v\t%v\n"},
- {"psx", "core.psx", 0}, {"list", "system.listMethods", 0},
- {"ls", "system.listMethods", 0}, {"ver", "core.version", 0},
- {"version", "core.version", 0},
- {"who", "ctl.who", "[%v] %v: %v %v -> %v %v\n"},
- {"listen", "ctl.listen", "[%v] %v: %v %v\n"},
- {"dns_mem_info", "dns.mem_info", "%v / %v\n"},
- {"dns_debug", "dns.debug",
- "%v (%v): size=%v ref=%v expire=%vs last=%vs ago f=%v\n"},
- {"dns_debug_all", "dns.debug_all",
- "%v (%v) [%v]: size=%v ref=%v expire=%vs last=%vs ago f=%v\n"
- "\t\t%v:%v expire=%vs f=%v\n"},
- {"dst_blocklist_mem_info", "dst_blocklist.mem_info", "%v / %v\n"},
- {"dst_blocklist_debug", "dst_blocklist.debug",
- "%v:%v:%v expire:%v flags: %v\n"},
- {0, 0, 0}};
- static struct kamcmd_builtin builtins[] = {{"?", kamcmd_help, "help"},
- {"help", kamcmd_help, "displays help for a command"},
- {"version", kamcmd_ver, "displays " NAME "version"},
- {"quit", kamcmd_quit, "exits " NAME},
- {"exit", kamcmd_quit, "exits " NAME},
- {"warranty", kamcmd_warranty, "displays " NAME "'s warranty info"},
- {"license", kamcmd_warranty, "displays " NAME "'s license"}, {0, 0}};
- #ifdef USE_READLINE
- enum complete_states
- {
- COMPLETE_INIT,
- COMPLETE_CMD_NAME,
- #ifdef USE_CFG_VARS
- COMPLETE_CFG_GRP,
- COMPLETE_CFG_VAR,
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- COMPLETE_CNT_GRP,
- COMPLETE_CNT_VAR,
- #endif /* USE_COUNTERS */
- COMPLETE_NOTHING
- };
- /* instead of rl_attempted_completion_over which is not present in
- some readline emulations, use attempted_completion_state */
- static enum complete_states attempted_completion_state;
- static int crt_param_no;
- /* commands for which we complete the params to other method names */
- char *complete_params_methods[] = {
- "?", "h", "help", "system.methodSignature", "system.methodHelp", 0};
- #ifdef USE_CFG_VARS
- /* commands for which we complete the first param with a cfg var grp*/
- char *complete_params_cfg_var[] = {"cfg.get", "cfg.help", "cfg.set_delayed_int",
- "cfg.set_delayed_string", "cfg.set_now_int", "cfg.set_now_string", 0};
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- /* commands for which we complete the first param with a counter group */
- char *complete_param1_counter_grp[] = {"cnt.get", "cnt.get_raw",
- "cnt.grp_get_all", "cnt.reset", "cnt.var_list", "cnt.help", 0};
- /* commands for which we completed the 2nd param with a counter name */
- char *complete_param2_counter_name[] = {
- "cnt.get", "cnt.get_raw", "cnt.reset", "cnt.help", 0};
- #endif /* USE_COUNTERS */
- #endif /* USE_READLINE */
- static int parse_arg(struct binrpc_val *v, char *arg)
- {
- int i;
- double f;
- char *tmp;
- int len;
- i = strtol(arg, &tmp, 10);
- if((tmp == 0) || (*tmp)) {
- f = strtod(arg, &tmp);
- if((tmp == 0) || (*tmp)) {
- /* not an int or a float => string */
- len = strlen(arg);
- if((len >= 2) && (arg[0] == 's') && (arg[1] == ':')) {
- tmp = &arg[2];
- len -= 2;
- } else {
- tmp = arg;
- }
- v->type = BINRPC_T_STR;
- v->u.strval.s = tmp;
- v->u.strval.len = len;
- } else { /* float */
- v->type = BINRPC_T_DOUBLE;
- v->u.fval = f;
- }
- } else { /* int */
- v->type = BINRPC_T_INT;
- v->u.intval = i;
- }
- return 0;
- }
- static int parse_cmd(struct binrpc_cmd *cmd, char **argv, int count)
- {
- int r;
- cmd->method = argv[0];
- if((count - 1) > MAX_BINRPC_ARGS) {
- fprintf(stderr, "ERROR: too many args %d, only %d allowed\n", count - 1,
- MAX_BINRPC_ARGS);
- return -1;
- }
- for(r = 1; r < count; r++) {
- if(parse_arg(&cmd->argv[r - 1], argv[r]) < 0)
- return -1;
- }
- cmd->argc = r - 1;
- return 0;
- }
- void print_binrpc_val(struct binrpc_val *v, int ident)
- {
- int r;
- if((v->type == BINRPC_T_STRUCT) && !v->u.end)
- ident--; /* fix to have struct beg. idented differently */
- for(r = 0; r < ident; r++)
- putchar(' ');
- if(v->name.s) {
- printf("%.*s: ", v->name.len, v->name.s);
- }
- switch(v->type) {
- case BINRPC_T_INT:
- printf("%d", v->u.intval);
- break;
- case BINRPC_T_STR:
- case BINRPC_T_BYTES:
- printf("%.*s", v->u.strval.len, v->u.strval.s);
- break;
- case BINRPC_T_ARRAY:
- printf("%c", (v->u.end) ? ']' : '[');
- break;
- case BINRPC_T_STRUCT:
- printf("%c", (v->u.end) ? '}' : '{');
- break;
- case BINRPC_T_DOUBLE:
- if(v->u.fval == (double)((long long int)v->u.fval)) {
- printf("%lld", (long long int)v->u.fval);
- } else {
- printf("%f", v->u.fval);
- }
- break;
- default:
- printf("ERROR: unknown type %d\n", v->type);
- };
- }
- /* opens, and connects on a STREAM unix socket
- * returns socket fd or -1 on error */
- int connect_unix_sock(char *name, int type)
- {
- struct sockaddr_un ifsun;
- int s;
- int len;
- int ret;
- int retries;
- retries = 0;
- s = -1;
- memset(&ifsun, 0, sizeof(struct sockaddr_un));
- len = strlen(name);
- if(len > UNIX_PATH_MAX) {
- fprintf(stderr,
- "ERROR: connect_unix_sock: name too long "
- "(%d > %d): %s\n",
- len, UNIX_PATH_MAX, name);
- goto error;
- }
- ifsun.sun_family = AF_UNIX;
- memcpy(ifsun.sun_path, name, len);
- #ifdef HAVE_SOCKADDR_SA_LEN
- ifsun.sun_len = len;
- #endif
- s = socket(PF_UNIX, type, 0);
- if(s == -1) {
- fprintf(stderr,
- "ERROR: connect_unix_sock: cannot create unix socket"
- " %s: %s [%d]\n",
- name, strerror(errno), errno);
- goto error;
- }
- if(type == SOCK_DGRAM) {
- /* we must bind so that we can receive replies */
- if(reply_socket == 0) {
- if(sock_dir == 0)
- sock_dir = "/tmp";
- retry:
- ret = snprintf(mysun.sun_path, UNIX_PATH_MAX, "%s/" NAME "_%d",
- sock_dir, rand());
- if((ret < 0) || (ret >= UNIX_PATH_MAX)) {
- fprintf(stderr, "ERROR: buffer overflow while trying to"
- "generate unix datagram socket name");
- goto error;
- }
- } else {
- if(strlen(reply_socket) > UNIX_PATH_MAX) {
- fprintf(stderr,
- "ERROR: buffer overflow while trying to"
- "use the provided unix datagram socket name (%s)",
- reply_socket);
- goto error;
- }
- strcpy(mysun.sun_path, reply_socket);
- }
- mysun.sun_family = AF_UNIX;
- if(bind(s, (struct sockaddr *)&mysun, sizeof(mysun)) == -1) {
- if(errno == EADDRINUSE && (reply_socket == 0) && (retries < 10)) {
- retries++;
- /* try another one */
- goto retry;
- }
- fprintf(stderr,
- "ERROR: could not bind the unix socket to"
- " %s: %s (%d)\n",
- mysun.sun_path, strerror(errno), errno);
- goto error;
- }
- unix_socket = mysun.sun_path;
- }
- if(connect(s, (struct sockaddr *)&ifsun, sizeof(ifsun)) == -1) {
- fprintf(stderr, "ERROR: connect_unix_sock: connect(%s): %s [%d]\n",
- name, strerror(errno), errno);
- goto error;
- }
- return s;
- error:
- if(s != -1)
- close(s);
- return -1;
- }
- int connect_tcpudp_socket(char *address, int port, int type)
- {
- struct sockaddr_in addr;
- struct hostent *he;
- int sock;
- sock = -1;
- /* resolve destination */
- he = gethostbyname(address);
- if(he == 0) {
- fprintf(stderr, "ERROR: could not resolve %s\n", address);
- goto error;
- }
- /* open socket*/
- addr.sin_family = he->h_addrtype;
- addr.sin_port = htons(port);
- memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
- sock = socket(he->h_addrtype, type, 0);
- if(sock == -1) {
- fprintf(stderr, "ERROR: socket: %s\n", strerror(errno));
- goto error;
- }
- if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) != 0) {
- fprintf(stderr, "ERROR: connect: %s\n", strerror(errno));
- goto error;
- }
- return sock;
- error:
- if(sock != -1)
- close(sock);
- return -1;
- }
- static void hexdump(unsigned char *buf, int len, int ascii)
- {
- int r, i;
- /* dump it in hex */
- for(r = 0; r < len; r++) {
- if((r) && ((r % 16) == 0)) {
- if(ascii) {
- putchar(' ');
- for(i = r - 16; i < r; i++) {
- if(isprint(buf[i]))
- putchar(buf[i]);
- else
- putchar('.');
- }
- }
- putchar('\n');
- }
- printf("%02x ", buf[r]);
- };
- if(ascii) {
- for(i = r; i % 16; i++)
- printf(" ");
- putchar(' ');
- for(i = 16 * (r / 16); i < r; i++) {
- if(isprint(buf[i]))
- putchar(buf[i]);
- else
- putchar('.');
- }
- }
- putchar('\n');
- }
- /* returns: -1 on error, number of bytes written on success */
- static int send_binrpc_cmd(int s, struct binrpc_cmd *cmd, int cookie)
- {
- struct iovec v[IOVEC_CNT];
- int r;
- unsigned char msg_body[MAX_BODY_SIZE];
- unsigned char msg_hdr[BINRPC_MAX_HDR_SIZE];
- struct binrpc_pkt body;
- int ret;
- int n;
- ret = binrpc_init_pkt(&body, msg_body, MAX_BODY_SIZE);
- if(ret < 0)
- goto binrpc_err;
- ret = binrpc_addstr(&body, cmd->method, strlen(cmd->method));
- if(ret < 0)
- goto binrpc_err;
- for(r = 0; r < cmd->argc; r++) {
- switch(cmd->argv[r].type) {
- case BINRPC_T_STR:
- ret = binrpc_addstr(&body, cmd->argv[r].u.strval.s,
- cmd->argv[r].u.strval.len);
- break;
- case BINRPC_T_INT:
- ret = binrpc_addint(&body, cmd->argv[r].u.intval);
- break;
- case BINRPC_T_DOUBLE:
- ret = binrpc_adddouble(&body, cmd->argv[r].u.fval);
- break;
- default:
- fprintf(stderr, "ERROR: unsupported type %d\n",
- cmd->argv[r].type);
- }
- if(ret < 0)
- goto binrpc_err;
- }
- ret = binrpc_build_hdr(BINRPC_REQ, binrpc_pkt_len(&body), cookie, msg_hdr,
- BINRPC_MAX_HDR_SIZE);
- if(ret < 0)
- goto binrpc_err;
- v[0].iov_base = msg_hdr;
- v[0].iov_len = ret;
- v[1].iov_base = msg_body;
- v[1].iov_len = binrpc_pkt_len(&body);
- write_again:
- if((n = writev(s, v, 2)) < 0) {
- if(errno == EINTR)
- goto write_again;
- goto error_send;
- }
- return n;
- error_send:
- return -1;
- binrpc_err:
- return -2;
- }
- static int binrpc_errno = 0;
- /* reads the whole reply
- * returns < 0 on error, reply size on success + initializes in_pkt
- * if ret==-2 (parse error), sets binrpc_errno to the binrpc error
- * error returns: -1 - read error (check errno)
- * -2 - binrpc parse error (check binrpc_errno)
- * -3 - cookie error (the cookied doesn't match)
- * -4 - message too big */
- static int get_reply(int s, unsigned char *reply_buf, int max_reply_size,
- int cookie, struct binrpc_parse_ctx *in_pkt, unsigned char **body)
- {
- unsigned char *crt;
- unsigned char *hdr_end;
- unsigned char *msg_end;
- int n;
- int ret;
- hdr_end = crt = reply_buf;
- msg_end = reply_buf + max_reply_size;
- binrpc_errno = 0;
- do {
- n = read(s, crt, (int)(msg_end - crt));
- if(n <= 0) {
- if(errno == EINTR)
- continue;
- goto error_read;
- }
- if(verbose >= 3) {
- /* dump it in hex */
- printf("received %d bytes in reply (@offset %d):\n", n,
- (int)(crt - reply_buf));
- hexdump(crt, n, 1);
- }
- crt += n;
- /* parse header if not parsed yet */
- if(hdr_end == reply_buf) {
- hdr_end = binrpc_parse_init(in_pkt, reply_buf, n, &ret);
- if(ret < 0) {
- if(ret == E_BINRPC_MORE_DATA)
- continue;
- goto error_parse;
- }
- if(verbose > 1) {
- printf("new packet: type %02x, len %d, cookie %02x\n",
- in_pkt->type, in_pkt->tlen, in_pkt->cookie);
- }
- if(in_pkt->cookie != cookie) {
- fprintf(stderr,
- "bad reply, cookie doesn't match: sent %02x "
- "and received %02x\n",
- cookie, in_pkt->cookie);
- goto error;
- }
- msg_end = hdr_end + in_pkt->tlen;
- if((int)(msg_end - reply_buf) > max_reply_size) {
- /* reading the rest from the socket */
- struct timeval timeout_save;
- unsigned sizeoft = sizeof(timeout_save);
- if(getsockopt(
- s, SOL_SOCKET, SO_RCVTIMEO, &timeout_save, &sizeoft)
- == 0) {
- struct timeval timeout;
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
- if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout))
- == 0) {
- while(read(s, reply_buf, max_reply_size) > 0)
- ;
- setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
- (char *)&timeout_save, sizeof(timeout_save));
- }
- }
- goto error_toolong;
- }
- }
- } while(crt < msg_end);
- *body = hdr_end;
- return (int)(msg_end - reply_buf);
- error_read:
- return -1;
- error_parse:
- binrpc_errno = ret;
- return -2;
- error:
- return -3;
- error_toolong:
- return -4;
- }
- /* returns a malloced copy of str, with all the escapes ('\') resolved */
- static char *str_escape(char *str)
- {
- char *n;
- char *ret;
- ret = n = malloc(strlen(str) + 1);
- if(n == 0)
- goto end;
- for(; *str; str++) {
- *n = *str;
- if(*str == '\\') {
- switch(*(str + 1)) {
- case 'n':
- *n = '\n';
- str++;
- break;
- case 'r':
- *n = '\r';
- str++;
- break;
- case 't':
- *n = '\t';
- str++;
- break;
- case '\\':
- str++;
- break;
- }
- }
- n++;
- }
- *n = *str; /* terminating 0 */
- end:
- return ret;
- }
- /* parses strings like "bla bla %v 10%% %v\n test=%v",
- * and stops at each %v, returning a pointer after the %v, setting *size
- * to the string length (not including %v) and *type to the corresponding
- * BINRPC type (for now only BINRPC_T_ALL).
- * To escape a '%', use "%%", and check for type==-1 (which means skip a call
- * again parse_fmt).
- * Usage:
- * n="test: %v,%v,%v\n";
- * while(*n){
- * s=n;
- * n=parse_fmt(n, &type, &size);
- * printf("%.*s", size, s);
- * if (type==-1)
- * continue;
- * else
- * printf("now we should get & print an object of type %d\n", type)
- * }
- */
- static char *parse_fmt(char *fmt, int *type, int *size)
- {
- char *s;
- s = fmt;
- do {
- for(; *fmt && *fmt != '%'; fmt++)
- ;
- if(*fmt == '%') {
- switch(*(fmt + 1)) {
- case 'v':
- *type = BINRPC_T_ALL;
- *size = (int)(fmt - s);
- return (fmt + 2);
- break;
- case '%':
- /* escaped % */
- *size = (int)(fmt - s) + 1;
- *type = -1; /* skip */
- return (fmt + 2);
- break;
- }
- }
- } while(*fmt);
- *type = -1; /* no value */
- *size = (fmt - s);
- return fmt;
- }
- static int print_body(struct binrpc_parse_ctx *in_pkt, unsigned char *body,
- int size, char *fmt)
- {
- unsigned char *p;
- unsigned char *end;
- struct binrpc_val val;
- int ret;
- int rec;
- char *f;
- char *s;
- int f_size;
- int fmt_has_values;
- p = body;
- end = p + size;
- rec = 0;
- f = fmt;
- fmt_has_values = 0;
- /* read body */
- while(p < end) {
- if(f) {
- do {
- if(*f == 0)
- f = fmt; /* reset */
- s = f;
- f = parse_fmt(f, &val.type, &f_size);
- printf("%.*s", f_size, s);
- if(val.type != -1) {
- fmt_has_values = 1;
- goto read_value;
- }
- } while(*f || fmt_has_values);
- val.type = BINRPC_T_ALL;
- } else {
- val.type = BINRPC_T_ALL;
- }
- read_value:
- val.name.s = 0;
- val.name.len = 0;
- p = binrpc_read_record(in_pkt, p, end, &val, 1, &ret);
- if(ret < 0) {
- if(fmt)
- putchar('\n');
- /*if (ret==E_BINRPC_MORE_DATA)
- goto error_read_again;*/
- if(ret == E_BINRPC_EOP) {
- printf("end of message detected\n");
- break;
- }
- fprintf(stderr,
- "ERROR:: while parsing the record %d,"
- " @%d: %02x : %s\n",
- rec, in_pkt->offset, *p, binrpc_error(ret));
- goto error;
- }
- rec++;
- if(fmt) {
- print_binrpc_val(&val, 0);
- } else {
- print_binrpc_val(&val, in_pkt->in_struct + in_pkt->in_array);
- putchar('\n');
- }
- }
- if(fmt && *f) {
- /* print the rest, with empty values */
- while(*f) {
- s = f;
- f = parse_fmt(f, &val.type, &f_size);
- printf("%.*s", f_size, s);
- }
- }
- return 0;
- error:
- return -1;
- /*error_read_again:
- fprintf(stderr, "ERROR: more data needed\n");
- return -2;
- */
- }
- static int print_fault(
- struct binrpc_parse_ctx *in_pkt, unsigned char *body, int size)
- {
- printf("error: ");
- return print_body(in_pkt, body, size, "%v - %v\n");
- }
- static int run_binrpc_cmd(int s, struct binrpc_cmd *cmd, char *fmt)
- {
- int cookie;
- unsigned char reply_buf[MAX_REPLY_SIZE];
- unsigned char *msg_body;
- struct binrpc_parse_ctx in_pkt;
- int ret;
- cookie = gen_cookie();
- if((ret = send_binrpc_cmd(s, cmd, cookie)) < 0) {
- if(ret == -1)
- goto error_send;
- else
- goto binrpc_err;
- }
- /* read reply */
- memset(&in_pkt, 0, sizeof(in_pkt));
- if((ret = get_reply(
- s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt, &msg_body))
- < 0) {
- switch(ret) {
- case -1:
- goto error_read;
- case -2:
- goto error_parse;
- case -3:
- goto error_cookie;
- case -4:
- goto error_toobig;
- }
- goto error;
- }
- switch(in_pkt.type) {
- case BINRPC_FAULT:
- if(print_fault(&in_pkt, msg_body, in_pkt.tlen) < 0) {
- goto error;
- }
- break;
- case BINRPC_REPL:
- if(print_body(&in_pkt, msg_body, in_pkt.tlen, fmt) < 0) {
- goto error;
- }
- break;
- default:
- fprintf(stderr, "ERROR: not a reply\n");
- goto error;
- }
- if(verbose)
- printf(".\n");
- /* normal exit */
- return 0;
- binrpc_err:
- fprintf(stderr, "ERROR while building the packet: %s\n", binrpc_error(ret));
- goto error;
- error_parse:
- fprintf(stderr, "ERROR while parsing the reply: %s\n",
- binrpc_error(binrpc_errno));
- goto error;
- error_cookie:
- fprintf(stderr, "ERROR: cookie does not match\n");
- goto error;
- error_toobig:
- fprintf(stderr, "ERROR: reply too big\n");
- goto error;
- error_send:
- fprintf(stderr, "ERROR: send packet failed: %s (%d)\n", strerror(errno),
- errno);
- goto error;
- error_read:
- fprintf(stderr, "ERROR: read reply failed: %s (%d)\n", strerror(errno),
- errno);
- goto error;
- error:
- return -1;
- }
- static int parse_line(struct binrpc_cmd *cmd, char *line)
- {
- char *p;
- int count;
- cmd->method = strtok(line, " \t");
- if(cmd->method == 0)
- goto error_no_method;
- count = 0;
- for(p = strtok(0, " \t"); p; p = strtok(0, " \t")) {
- if(count >= MAX_BINRPC_ARGS)
- goto error_too_many;
- if(parse_arg(&cmd->argv[count], p) < 0) {
- goto error_arg;
- }
- count++;
- }
- cmd->argc = count;
- return 0;
- error_no_method:
- printf("ERROR: no method name\n");
- return -1;
- error_too_many:
- printf("ERROR: too many arguments (%d), no more than %d allowed\n", count,
- MAX_BINRPC_ARGS);
- return -1;
- error_arg:
- printf("ERROR: bad argument %d: %s\n", count + 1, p);
- return -1;
- }
- /* resolves builtin aliases */
- static void fix_cmd(struct binrpc_cmd *cmd, char **format)
- {
- int r;
- for(r = 0; cmd_aliases[r].name; r++) {
- if(strcmp(cmd_aliases[r].name, cmd->method) == 0) {
- cmd->method = cmd_aliases[r].method;
- if(*format == 0)
- *format = cmd_aliases[r].format;
- break;
- }
- }
- }
- /* intercept builtin commands, returns 1 if intercepted, 0 if not, <0 on error
- */
- static int run_builtins(int s, struct binrpc_cmd *cmd)
- {
- int r;
- int ret;
- for(r = 0; builtins[r].name; r++) {
- if(strcmp(builtins[r].name, cmd->method) == 0) {
- ret = builtins[r].f(s, cmd);
- return (ret < 0) ? ret : 1;
- }
- }
- return 0;
- }
- /* runs command from cmd */
- inline static int run_cmd(int s, struct binrpc_cmd *cmd, char *format)
- {
- int ret;
- char *fmt;
- fmt = format;
- fix_cmd(cmd, &fmt);
- if(!(ret = run_builtins(s, cmd))) {
- ret = run_binrpc_cmd(s, cmd, fmt);
- }
- return (ret > 0) ? 0 : ret;
- }
- /* runs a command represented in line */
- inline static int run_line(int s, char *l, char *format)
- {
- struct binrpc_cmd cmd;
- int ret;
- if((ret = parse_line(&cmd, l)) == 0) {
- return run_cmd(s, &cmd, format);
- }
- return ret;
- }
- static void free_rpc_array(struct binrpc_val *a, int size)
- {
- int r;
- for(r = 0; r < size; r++) {
- if(a[r].name.s)
- free(a[r].name.s);
- if((a[r].type == BINRPC_T_STR || a[r].type == BINRPC_T_BYTES)
- && a[r].u.strval.s) {
- free(a[r].u.strval.s);
- }
- }
- free(a);
- }
- /* parse the body into a malloc allocated, binrpc_val array */
- static struct binrpc_val *parse_reply_body(int *records,
- struct binrpc_parse_ctx *in_pkt, unsigned char *body, int size)
- {
- struct binrpc_val *a;
- struct binrpc_val *t;
- unsigned char *p;
- unsigned char *end;
- struct binrpc_val val;
- int ret;
- int rec;
- rec = 0;
- if(*records == 0) {
- *records = 100; /* start with a reasonable size */
- };
- a = malloc(*records * sizeof(struct binrpc_val));
- if(a == 0)
- goto error_mem;
- p = body;
- end = p + size;
- /* read body */
- while(p < end) {
- val.type = BINRPC_T_ALL;
- val.name.s = 0;
- val.name.len = 0;
- p = binrpc_read_record(in_pkt, p, end, &val, 1, &ret);
- if(ret < 0) {
- if(ret == E_BINRPC_EOP) {
- printf("end of message detected\n");
- break;
- }
- fprintf(stderr,
- "ERROR: while parsing the record %d,"
- " @%d: %02x : %s\n",
- rec, in_pkt->offset, *p, binrpc_error(ret));
- goto error;
- }
- if(rec >= *records) {
- t = realloc(a, *records * sizeof(struct binrpc_val) * 2);
- if(t == 0)
- goto error_mem;
- a = t;
- *records *= 2;
- }
- a[rec] = val;
- if(val.name.s) {
- if((a[rec].name.s = malloc(val.name.len + 1)) == 0)
- goto error_mem;
- memcpy(a[rec].name.s, val.name.s, val.name.len);
- a[rec].name.s[val.name.len + 1] = 0; /* 0-term */
- }
- if(val.u.strval.s) {
- if(val.type == BINRPC_T_STR) {
- if((a[rec].u.strval.s = malloc(val.u.strval.len + 1)) == 0)
- goto error_mem;
- memcpy(a[rec].u.strval.s, val.u.strval.s, val.u.strval.len);
- a[rec].u.strval.s[val.u.strval.len] = 0; /* 0-term */
- } else if(val.type == BINRPC_T_BYTES) {
- if((a[rec].u.strval.s = malloc(val.u.strval.len)) == 0)
- goto error_mem;
- memcpy(a[rec].u.strval.s, val.u.strval.s, val.u.strval.len);
- }
- }
- rec++;
- }
- if(rec && (rec < *records)) {
- a = realloc(a, rec * sizeof(struct binrpc_val));
- }
- *records = rec;
- return a;
- error_mem:
- fprintf(stderr, "ERROR: parse_reply_body: out of memory\n");
- error:
- if(a) {
- free_rpc_array(a, rec);
- }
- *records = 0;
- return 0;
- }
- static int get_kamcmd_list(int s)
- {
- struct binrpc_cmd cmd;
- int cookie;
- unsigned char reply_buf[MAX_REPLY_SIZE];
- unsigned char *msg_body;
- struct binrpc_parse_ctx in_pkt;
- int ret;
- cmd.method = "system.listMethods";
- cmd.argc = 0;
- cookie = gen_cookie();
- if((ret = send_binrpc_cmd(s, &cmd, cookie)) < 0) {
- if(ret == -1)
- goto error_send;
- else
- goto binrpc_err;
- }
- /* read reply */
- memset(&in_pkt, 0, sizeof(in_pkt));
- if((ret = get_reply(
- s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt, &msg_body))
- < 0) {
- goto error;
- }
- switch(in_pkt.type) {
- case BINRPC_FAULT:
- if(print_fault(&in_pkt, msg_body, in_pkt.tlen) < 0) {
- goto error;
- }
- break;
- case BINRPC_REPL:
- rpc_no = 100; /* default cmd list */
- if((rpc_array = parse_reply_body(
- &rpc_no, &in_pkt, msg_body, in_pkt.tlen))
- == 0)
- goto error;
- break;
- default:
- fprintf(stderr, "ERROR: not a reply\n");
- goto error;
- }
- return 0;
- binrpc_err:
- error_send:
- error:
- return -1;
- }
- #if defined(USE_CFG_VARS) || defined(USE_COUNTERS)
- /** check if cmd is a rpc command.
- * Quick check (using the internal rpc_array) if cmd is a valid rpc command.
- * @param cmd - null terminated ascii string
- * @return 1 on success, 0 on failure.
- */
- static int is_rpc_cmd(char *cmd)
- {
- int r;
- int cmd_len;
- cmd_len = strlen(cmd);
- for(r = 0; r < rpc_no; r++) {
- if((rpc_array[r].type == BINRPC_T_STR)
- && (rpc_array[r].u.strval.len == cmd_len)
- && (strncmp(cmd, rpc_array[r].u.strval.s, cmd_len) == 0))
- return 1;
- }
- return 0;
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_CFG_VARS
- /* retrieve the cfg vars and group list */
- static int get_cfgvars_list(int s)
- {
- struct binrpc_cmd cmd;
- int cookie;
- unsigned char reply_buf[MAX_REPLY_SIZE];
- unsigned char *msg_body;
- struct binrpc_parse_ctx in_pkt;
- struct cfg_var_grp *grp;
- struct cfg_var_grp *last_grp;
- char *p;
- char *end;
- str grp_name;
- str var_name;
- int r;
- int ret;
- cmd.method = "cfg.list";
- cmd.argc = 0;
- if(!is_rpc_cmd(cmd.method))
- goto error;
- cookie = gen_cookie();
- if((ret = send_binrpc_cmd(s, &cmd, cookie)) < 0) {
- if(ret == -1)
- goto error_send;
- else
- goto binrpc_err;
- }
- /* read reply */
- memset(&in_pkt, 0, sizeof(in_pkt));
- if((ret = get_reply(
- s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt, &msg_body))
- < 0) {
- goto error;
- }
- switch(in_pkt.type) {
- case BINRPC_FAULT:
- if(print_fault(&in_pkt, msg_body, in_pkt.tlen) < 0) {
- goto error;
- }
- break;
- case BINRPC_REPL:
- cfg_vars_no = 100; /* default cmd list */
- if((cfg_vars_array = parse_reply_body(
- &cfg_vars_no, &in_pkt, msg_body, in_pkt.tlen))
- == 0)
- goto error;
- break;
- default:
- fprintf(stderr, "ERROR: not a reply\n");
- goto error;
- }
- /* get the config groups */
- last_grp = 0;
- for(r = 0; r < cfg_vars_no; r++) {
- grp_name.s = 0;
- grp_name.len = 0;
- if(cfg_vars_array[r].type != BINRPC_T_STR)
- continue;
- grp_name.s = cfg_vars_array[r].u.strval.s;
- end = cfg_vars_array[r].u.strval.len + grp_name.s;
- /* parse <grp>: <var_name>*/
- for(p = grp_name.s; p < end; p++) {
- if(*p == ':') {
- grp_name.len = (int)(long)(p - grp_name.s);
- break;
- }
- }
- for(grp = cfg_grp_lst; grp; grp = grp->next) {
- if(grp->grp_name.len == grp_name.len
- && memcmp(grp->grp_name.s, grp_name.s, grp_name.len) == 0) {
- break; /* found */
- }
- }
- if(grp == 0) {
- /* not found => create a new one */
- grp = malloc(sizeof(*grp));
- if(grp == 0)
- goto error_mem;
- memset(grp, 0, sizeof(*grp));
- grp->grp_name = grp_name;
- if(last_grp) {
- last_grp->next = grp;
- last_grp = grp;
- } else {
- cfg_grp_lst = grp;
- last_grp = cfg_grp_lst;
- }
- }
- grp->var_no++;
- }
- /* alloc the var arrays per group */
- for(grp = cfg_grp_lst; grp; grp = grp->next) {
- grp->var_names = malloc(sizeof(str) * grp->var_no);
- if(grp->var_names == 0)
- goto error_mem;
- memset(grp->var_names, 0, sizeof(str) * grp->var_no);
- grp->var_no = 0;
- }
- /* reparse to get the var names per group */
- for(r = 0; r < cfg_vars_no; r++) {
- grp_name.s = 0;
- grp_name.len = 0;
- var_name.s = 0;
- var_name.len = 0;
- if(cfg_vars_array[r].type != BINRPC_T_STR)
- continue;
- grp_name.s = cfg_vars_array[r].u.strval.s;
- end = cfg_vars_array[r].u.strval.len + grp_name.s;
- /* parse <grp>: <var_name>*/
- for(p = grp_name.s; p < end; p++) {
- if(*p == ':') {
- grp_name.len = (int)(long)(p - grp_name.s);
- p++;
- for(; p < end && *p == ' '; p++)
- ;
- var_name.s = p;
- var_name.len = (int)(long)(end - p);
- if(var_name.len == 0)
- break;
- for(grp = cfg_grp_lst; grp; grp = grp->next) {
- if(grp->grp_name.len == grp_name.len
- && memcmp(grp->grp_name.s, grp_name.s, grp_name.len)
- == 0) {
- /* add var */
- grp->var_names[grp->var_no] = var_name;
- grp->var_no++;
- }
- }
- break;
- }
- }
- }
- return 0;
- binrpc_err:
- error_send:
- error:
- error_mem:
- return -1;
- }
- void free_cfg_grp_lst()
- {
- struct cfg_var_grp *grp;
- struct cfg_var_grp *last;
- grp = cfg_grp_lst;
- while(grp) {
- last = grp;
- grp = grp->next;
- if(last->var_names)
- free(last->var_names);
- free(last);
- }
- cfg_grp_lst = 0;
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- /* retrieve the counters names and group list */
- static int get_counters_list(int s)
- {
- struct binrpc_cmd cmd;
- int cookie;
- unsigned char reply_buf[MAX_REPLY_SIZE];
- unsigned char *msg_body;
- struct binrpc_parse_ctx in_pkt;
- struct cnt_var_grp *grp;
- struct cnt_var_grp *last_grp;
- str grp_name;
- str var_name;
- int r;
- int ret;
- cmd.method = "cnt.grps_list";
- cmd.argc = 0;
- if(!is_rpc_cmd(cmd.method))
- goto error;
- cookie = gen_cookie();
- if((ret = send_binrpc_cmd(s, &cmd, cookie)) < 0) {
- if(ret == -1)
- goto error_send;
- else
- goto binrpc_err;
- }
- /* read reply */
- memset(&in_pkt, 0, sizeof(in_pkt));
- if((ret = get_reply(
- s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt, &msg_body))
- < 0) {
- goto error;
- }
- switch(in_pkt.type) {
- case BINRPC_FAULT:
- if(print_fault(&in_pkt, msg_body, in_pkt.tlen) < 0) {
- goto error;
- }
- break;
- case BINRPC_REPL:
- cnt_grps_no = 20; /* default counter list */
- if((cnt_grps_array = parse_reply_body(
- &cnt_grps_no, &in_pkt, msg_body, in_pkt.tlen))
- == 0)
- goto error;
- break;
- default:
- fprintf(stderr, "ERROR: not a reply\n");
- goto error;
- }
- /* get the config groups */
- last_grp = 0;
- for(r = 0; r < cnt_grps_no; r++) {
- grp_name.s = 0;
- grp_name.len = 0;
- if(cnt_grps_array[r].type != BINRPC_T_STR)
- continue;
- grp_name = cnt_grps_array[r].u.strval;
- /* check for duplicates */
- for(grp = cnt_grp_lst; grp; grp = grp->next) {
- if(grp->grp_name.len == grp_name.len
- && memcmp(grp->grp_name.s, grp_name.s, grp_name.len) == 0) {
- break; /* found */
- }
- }
- if(grp == 0) {
- /* not found => create a new one */
- grp = malloc(sizeof(*grp));
- if(grp == 0)
- goto error_mem;
- memset(grp, 0, sizeof(*grp));
- grp->grp_name = grp_name;
- if(last_grp) {
- last_grp->next = grp;
- last_grp = grp;
- } else {
- cnt_grp_lst = grp;
- last_grp = cnt_grp_lst;
- }
- }
- }
- /* gets vars per group */
- for(grp = cnt_grp_lst; grp; grp = grp->next) {
- cmd.method = "cnt.var_list";
- cmd.argv[0].type = BINRPC_T_STR;
- cmd.argv[0].u.strval = grp->grp_name;
- cmd.argc = 1;
- if(!is_rpc_cmd(cmd.method))
- goto error;
- cookie = gen_cookie();
- if((ret = send_binrpc_cmd(s, &cmd, cookie)) < 0) {
- if(ret == -1)
- goto error_send;
- else
- goto binrpc_err;
- }
- /* read reply */
- memset(&in_pkt, 0, sizeof(in_pkt));
- if((ret = get_reply(
- s, reply_buf, MAX_REPLY_SIZE, cookie, &in_pkt, &msg_body))
- < 0) {
- goto error;
- }
- switch(in_pkt.type) {
- case BINRPC_FAULT:
- if(print_fault(&in_pkt, msg_body, in_pkt.tlen) < 0) {
- goto error;
- }
- break;
- case BINRPC_REPL:
- grp->cnt_vars_no = 100; /* default counter list */
- if((grp->cnt_vars_array = parse_reply_body(
- &grp->cnt_vars_no, &in_pkt, msg_body, in_pkt.tlen))
- == 0)
- goto error;
- break;
- default:
- fprintf(stderr, "ERROR: not a reply\n");
- goto error;
- }
- grp->var_no = 0;
- grp->var_names = malloc(sizeof(str) * grp->cnt_vars_no);
- if(grp->var_names == 0)
- goto error_mem;
- memset(grp->var_names, 0, sizeof(str) * grp->cnt_vars_no);
- for(r = 0; r < grp->cnt_vars_no; r++) {
- if(grp->cnt_vars_array[r].type != BINRPC_T_STR)
- continue;
- var_name = grp->cnt_vars_array[r].u.strval;
- grp->var_names[grp->var_no] = var_name;
- grp->var_no++;
- }
- }
- return 0;
- binrpc_err:
- error_send:
- error:
- error_mem:
- return -1;
- }
- void free_cnt_grp_lst()
- {
- struct cnt_var_grp *grp;
- struct cnt_var_grp *last;
- grp = cnt_grp_lst;
- while(grp) {
- last = grp;
- grp = grp->next;
- if(last->cnt_vars_array)
- free_rpc_array(last->cnt_vars_array, last->cnt_vars_no);
- free(last);
- }
- cnt_grp_lst = 0;
- }
- #endif /* USE_COUNTERS */
- static void print_formatting(char *prefix, char *format, char *suffix)
- {
- if(format) {
- printf("%s", prefix);
- for(; *format; format++) {
- switch(*format) {
- case '\t':
- printf("\\t");
- break;
- case '\n':
- printf("\\n");
- break;
- case '\r':
- printf("\\r");
- break;
- default:
- putchar(*format);
- }
- }
- printf("%s", suffix);
- }
- }
- static int kamcmd_help(int s, struct binrpc_cmd *cmd)
- {
- int r;
- if(cmd->argc && (cmd->argv[0].type == BINRPC_T_STR)) {
- /* if it has args, try command help */
- for(r = 0; cmd_aliases[r].name; r++) {
- if(strcmp(cmd->argv[0].u.strval.s, cmd_aliases[r].name) == 0) {
- printf("%s is an alias for %s", cmd->argv[0].u.strval.s,
- cmd_aliases[r].method);
- print_formatting(" with reply formatting: \"",
- cmd_aliases[r].format, "\"");
- putchar('\n');
- return 0;
- }
- }
- for(r = 0; builtins[r].name; r++) {
- if(strcmp(cmd->argv[0].u.strval.s, builtins[r].name) == 0) {
- printf("builtin command: %s\n",
- builtins[r].doc ? builtins[r].doc : "undocumented");
- return 0;
- }
- }
- cmd->method = "system.methodHelp";
- if(run_binrpc_cmd(s, cmd, 0) < 0) {
- printf("error: no such command %s\n", cmd->argv[0].u.strval.s);
- }
- return 0;
- }
- if(rpc_no == 0) {
- if(get_kamcmd_list(s) < 0)
- goto error;
- }
- for(r = 0; r < rpc_no; r++) {
- if(rpc_array[r].type == BINRPC_T_STR) {
- printf("%s\n", rpc_array[r].u.strval.s);
- }
- }
- for(r = 0; cmd_aliases[r].name; r++) {
- printf("alias: %s\n", cmd_aliases[r].name);
- }
- for(r = 0; builtins[r].name; r++) {
- printf("builtin: %s\n", builtins[r].name);
- }
- return 0;
- error:
- return -1;
- }
- static int kamcmd_ver(int s, struct binrpc_cmd *cmd)
- {
- printf("%s\n", version);
- printf("%s compiled on %s \n", __FILE__, compiled);
- #ifdef USE_READLINE
- printf("interactive mode command completion support\n");
- #endif
- return 0;
- }
- static int kamcmd_quit(int s, struct binrpc_cmd *cmd)
- {
- quit = 1;
- return 0;
- }
- static int kamcmd_warranty(int s, struct binrpc_cmd *cmd)
- {
- printf("%s %s\n", NAME, VERSION);
- printf("%s\n", COPYRIGHT);
- printf("\n%s\n", LICENSE);
- return 0;
- }
- #ifdef USE_READLINE
- /* readline command generator */
- static char *kamcmd_generator(const char *text, int state)
- {
- static int idx;
- static int list; /* aliases, builtins, rpc_array */
- static int len;
- char *name;
- #ifdef USE_CFG_VARS
- static struct cfg_var_grp *grp;
- #endif
- #ifdef USE_COUNTERS
- static struct cnt_var_grp *cnt_grp;
- #endif
- switch(attempted_completion_state) {
- case COMPLETE_INIT:
- case COMPLETE_NOTHING:
- return 0;
- case COMPLETE_CMD_NAME:
- if(state == 0) {
- /* init */
- idx = list = 0;
- len = strlen(text);
- }
- /* return next partial match */
- switch(list) {
- case 0: /* aliases*/
- while((name = cmd_aliases[idx].name)) {
- idx++;
- if(strncmp(name, text, len) == 0)
- return strdup(name);
- }
- list++;
- idx = 0;
- /* no break */
- case 1: /* builtins */
- while((name = builtins[idx].name)) {
- idx++;
- if(strncmp(name, text, len) == 0)
- return strdup(name);
- }
- list++;
- idx = 0;
- /* no break */
- case 2: /* rpc_array */
- while(idx < rpc_no) {
- if(rpc_array[idx].type == BINRPC_T_STR) {
- name = rpc_array[idx].u.strval.s;
- idx++;
- if(strncmp(name, text, len) == 0)
- return strdup(name);
- } else {
- idx++;
- }
- }
- }
- break;
- #ifdef USE_CFG_VARS
- case COMPLETE_CFG_GRP:
- if(state == 0) {
- /* init */
- len = strlen(text);
- grp = cfg_grp_lst;
- } else {
- grp = grp->next;
- }
- for(; grp; grp = grp->next) {
- if(len <= grp->grp_name.len
- && memcmp(text, grp->grp_name.s, len) == 0) {
- /* zero-term copy of the grp name */
- name = malloc(grp->grp_name.len + 1);
- if(name) {
- memcpy(name, grp->grp_name.s, grp->grp_name.len);
- name[grp->grp_name.len] = 0;
- }
- return name;
- }
- }
- break;
- case COMPLETE_CFG_VAR:
- if(state == 0) {
- /* init */
- len = strlen(text);
- idx = 0;
- }
- while(idx < crt_cfg_grp->var_no) {
- if(len <= crt_cfg_grp->var_names[idx].len
- && memcmp(text, crt_cfg_grp->var_names[idx].s, len)
- == 0) {
- /* zero-term copy of the var name */
- name = malloc(crt_cfg_grp->var_names[idx].len + 1);
- if(name) {
- memcpy(name, crt_cfg_grp->var_names[idx].s,
- crt_cfg_grp->var_names[idx].len);
- name[crt_cfg_grp->var_names[idx].len] = 0;
- }
- idx++;
- return name;
- }
- idx++;
- }
- break;
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- case COMPLETE_CNT_GRP:
- if(state == 0) {
- /* init */
- len = strlen(text);
- cnt_grp = cnt_grp_lst;
- } else {
- cnt_grp = cnt_grp->next;
- }
- for(; cnt_grp; cnt_grp = cnt_grp->next) {
- if(len <= cnt_grp->grp_name.len
- && memcmp(text, cnt_grp->grp_name.s, len) == 0) {
- /* zero-term copy of the cnt_grp name */
- name = malloc(cnt_grp->grp_name.len + 1);
- if(name) {
- memcpy(name, cnt_grp->grp_name.s,
- cnt_grp->grp_name.len);
- name[cnt_grp->grp_name.len] = 0;
- }
- return name;
- }
- }
- break;
- case COMPLETE_CNT_VAR:
- if(state == 0) {
- /* init */
- len = strlen(text);
- idx = 0;
- }
- while(idx < crt_cnt_grp->var_no) {
- if(len <= crt_cnt_grp->var_names[idx].len
- && memcmp(text, crt_cnt_grp->var_names[idx].s, len)
- == 0) {
- /* zero-term copy of the var name */
- name = malloc(crt_cnt_grp->var_names[idx].len + 1);
- if(name) {
- memcpy(name, crt_cnt_grp->var_names[idx].s,
- crt_cnt_grp->var_names[idx].len);
- name[crt_cnt_grp->var_names[idx].len] = 0;
- }
- idx++;
- return name;
- }
- idx++;
- }
- break;
- #endif /* USE_COUNTERS */
- }
- /* no matches */
- return 0;
- }
- char **kamcmd_completion(const char *text, int start, int end)
- {
- int i, j;
- int cmd_start, cmd_end, cmd_len;
- int whitespace;
- #ifdef USE_CFG_VARS
- struct cfg_var_grp *grp;
- static int grp_start;
- int grp_len;
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- struct cnt_var_grp *cnt_grp;
- static int cnt_grp_start;
- int cnt_grp_len;
- #endif /* USE_COUNTERS */
- crt_param_no = 0;
- /* skip over whitespace at the beginning */
- for(j = 0; (j < start)
- && (rl_line_buffer[j] == ' ' || rl_line_buffer[j] == '\t');
- j++)
- ;
- cmd_start = j;
- if(start == cmd_start) {
- /* complete cmd name at beginning */
- attempted_completion_state = COMPLETE_CMD_NAME;
- #ifdef USE_CFG_VARS
- grp_start = 0;
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- cnt_grp_start = 0;
- #endif /* USE_COUNTERS */
- } else { /* or if this is a command for which we complete the parameters */
- /* find first whitespace after command name*/
- for(; (j < start) && (rl_line_buffer[j] != ' ')
- && (rl_line_buffer[j] != '\t');
- j++)
- ;
- cmd_end = j;
- cmd_len = cmd_end - cmd_start;
- /* count params before the current one */
- whitespace = 1;
- for(; j < start; j++) {
- if(rl_line_buffer[j] != ' ' && rl_line_buffer[j] != '\t') {
- if(whitespace)
- crt_param_no++;
- whitespace = 0;
- } else
- whitespace = 1;
- }
- crt_param_no++;
- if(crt_param_no == 1) {
- for(i = 0; complete_params_methods[i]; i++) {
- if((cmd_len == strlen(complete_params_methods[i]))
- && (strncmp(&rl_line_buffer[cmd_start],
- complete_params_methods[i], cmd_len)
- == 0)) {
- attempted_completion_state = COMPLETE_CMD_NAME;
- goto end;
- }
- }
- #ifdef USE_CFG_VARS
- /* try complete_param*_cfg_grp */
- for(i = 0; complete_params_cfg_var[i]; i++) {
- if((cmd_len == strlen(complete_params_cfg_var[i]))
- && (strncmp(&rl_line_buffer[cmd_start],
- complete_params_cfg_var[i], cmd_len)
- == 0)) {
- attempted_completion_state = COMPLETE_CFG_GRP;
- grp_start = start;
- goto end;
- }
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- /* try complete_param*_cfg_grp */
- for(i = 0; complete_param1_counter_grp[i]; i++) {
- if((cmd_len == strlen(complete_param1_counter_grp[i]))
- && (strncmp(&rl_line_buffer[cmd_start],
- complete_param1_counter_grp[i], cmd_len)
- == 0)) {
- attempted_completion_state = COMPLETE_CNT_GRP;
- cnt_grp_start = start;
- goto end;
- }
- }
- #endif /* USE_COUNTERS */
- } else if(crt_param_no == 2) {
- #ifdef USE_CFG_VARS
- /* see if we complete cfg. var names for this command */
- for(i = 0; complete_params_cfg_var[i]; i++) {
- if((cmd_len == strlen(complete_params_cfg_var[i]))
- && (strncmp(&rl_line_buffer[cmd_start],
- complete_params_cfg_var[i], cmd_len)
- == 0)) {
- /* get the group name: */
- /* find grp_start */
- for(j = cmd_end; (j < start)
- && ((rl_line_buffer[j] == ' ')
- || (rl_line_buffer[j] == '\t'));
- j++)
- ;
- grp_start = j;
- /* find group end / grp_len*/
- for(j = grp_start; (j < start) && (rl_line_buffer[j] != ' ')
- && (rl_line_buffer[j] != '\t');
- j++)
- ;
- grp_len = j - grp_start;
- for(grp = cfg_grp_lst; grp; grp = grp->next) {
- if(grp_len == grp->grp_name.len
- && memcmp(&rl_line_buffer[grp_start],
- grp->grp_name.s, grp_len)
- == 0) {
- attempted_completion_state = COMPLETE_CFG_VAR;
- crt_cfg_grp = grp;
- goto end;
- }
- }
- }
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- /* see if we complete counter names for this command */
- for(i = 0; complete_param2_counter_name[i]; i++) {
- if((cmd_len == strlen(complete_param2_counter_name[i]))
- && (strncmp(&rl_line_buffer[cmd_start],
- complete_param2_counter_name[i], cmd_len)
- == 0)) {
- /* get the group name: */
- /* find grp_start */
- for(j = cmd_end; (j < start)
- && ((rl_line_buffer[j] == ' ')
- || (rl_line_buffer[j] == '\t'));
- j++)
- ;
- cnt_grp_start = j;
- /* find group end / cnt_grp_len*/
- for(j = cnt_grp_start;
- (j < start) && (rl_line_buffer[j] != ' ')
- && (rl_line_buffer[j] != '\t');
- j++)
- ;
- cnt_grp_len = j - cnt_grp_start;
- for(cnt_grp = cnt_grp_lst; cnt_grp;
- cnt_grp = cnt_grp->next) {
- if(cnt_grp_len == cnt_grp->grp_name.len
- && memcmp(&rl_line_buffer[cnt_grp_start],
- cnt_grp->grp_name.s, cnt_grp_len)
- == 0) {
- attempted_completion_state = COMPLETE_CNT_VAR;
- crt_cnt_grp = cnt_grp;
- goto end;
- }
- }
- }
- }
- #endif /* COUNTERS */
- }
- attempted_completion_state = COMPLETE_NOTHING;
- }
- end:
- return 0; /* let readline call kamcmd_generator */
- }
- #endif /* USE_READLINE */
- /* on exit cleanup */
- static void cleanup()
- {
- if(unix_socket) {
- if(unlink(unix_socket) < 0) {
- fprintf(stderr, "ERROR: failed to delete %s: %s\n", unix_socket,
- strerror(errno));
- }
- }
- }
- int main(int argc, char **argv)
- {
- int c;
- char *sock_name;
- int sock_type;
- int s;
- struct binrpc_cmd cmd;
- struct id_list *sock_id;
- char *format;
- char *line;
- char *l;
- quit = 0;
- format = 0;
- line = 0;
- s = -1;
- sock_name = 0;
- sock_type = UNIXS_SOCK;
- opterr = 0;
- while((c = getopt(argc, argv, "UVhs:D:R:vf:")) != -1) {
- switch(c) {
- case 'V':
- printf("version: %s\n", version);
- printf("%s compiled on %s \n", __FILE__, compiled);
- exit(0);
- break;
- case 'h':
- printf("version: %s\n", version);
- printf("%s", help_msg);
- exit(0);
- break;
- case 's':
- sock_name = optarg;
- break;
- case 'R':
- reply_socket = optarg;
- break;
- case 'D':
- sock_dir = optarg;
- break;
- case 'U':
- sock_type = UDP_SOCK;
- break;
- case 'v':
- verbose++;
- break;
- case 'f':
- format = str_escape(optarg);
- if(format == 0) {
- fprintf(stderr, "ERROR: memory allocation failure\n");
- goto error;
- }
- break;
- case '?':
- if(isprint(optopt))
- fprintf(stderr, "Unknown option `-%c'.\n", optopt);
- else
- fprintf(stderr, "Unknown option character `\\x%x'.\n",
- optopt);
- goto error;
- case ':':
- fprintf(stderr, "Option `-%c' requires an argument.\n", optopt);
- goto error;
- default:
- abort();
- }
- }
- if(sock_name == 0) {
- sock_name = DEFAULT_CTL_SOCKET;
- }
- /* init the random number generator */
- srand(getpid() + time(0)); /* we don't need very strong random numbers */
- if(sock_name == 0) {
- fprintf(stderr, "ERROR: no server socket address specified\n");
- goto error;
- }
- sock_id = parse_listen_id(sock_name, strlen(sock_name), sock_type);
- if(sock_id == 0) {
- fprintf(stderr, "ERROR: error parsing server socket address %s\n",
- sock_name);
- goto error;
- }
- switch(sock_id->proto) {
- case UDP_SOCK:
- case TCP_SOCK:
- if(sock_id->port == 0) {
- sock_id->port = DEFAULT_CTL_PORT;
- /*
- fprintf(stderr, "ERROR: no port specified: %s:<port>\n",
- sock_name);
- goto error;
- */
- }
- if((s = connect_tcpudp_socket(sock_id->name, sock_id->port,
- (sock_id->proto == UDP_SOCK) ? SOCK_DGRAM
- : SOCK_STREAM))
- < 0) {
- goto error;
- }
- break;
- case UNIXS_SOCK:
- case UNIXD_SOCK:
- if((s = connect_unix_sock(sock_id->name,
- (sock_id->proto == UNIXD_SOCK) ? SOCK_DGRAM
- : SOCK_STREAM))
- < 0)
- goto error;
- break;
- case UNKNOWN_SOCK:
- fprintf(stderr, "ERROR: Bad socket type for %s\n", sock_name);
- goto error;
- }
- free(sock_id->buf); /* not needed anymore */
- free(sock_id); /* not needed anymore */
- sock_id = 0;
- if(optind >= argc) {
- /*fprintf(stderr, "ERROR: no command specified\n");
- goto error; */
- } else {
- if(parse_cmd(&cmd, &argv[optind], argc - optind) < 0)
- goto error;
- if(run_cmd(s, &cmd, format) < 0)
- goto error;
- goto end;
- }
- /* interactive mode */
- if(get_kamcmd_list(s) == 0) {
- #ifdef USE_CFG_VARS
- get_cfgvars_list(s);
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- get_counters_list(s);
- #endif /* USE_COUNTERS */
- }
- /* banners */
- printf("%s %s\n", NAME, VERSION);
- printf("%s\n", COPYRIGHT);
- printf("%s\n", DISCLAIMER);
- #ifdef USE_READLINE
- /* initialize readline */
- /* allow conditional parsing of the ~/.inputrc file*/
- rl_readline_name = NAME;
- rl_completion_entry_function = kamcmd_generator;
- rl_attempted_completion_function = kamcmd_completion;
- while(!quit) {
- line = readline(NAME "> ");
- if(line == 0) /* EOF */
- break;
- l = trim_ws(line); /* trim whitespace */
- if(*l) {
- add_history(l);
- run_line(s, l, format);
- }
- free(line);
- line = 0;
- }
- #else
- line = malloc(MAX_LINE_SIZE);
- if(line == 0) {
- fprintf(stderr, "memory allocation error\n");
- goto error;
- }
- printf(NAME "> ");
- fflush(stdout); /* prompt */
- while(!quit && fgets(line, MAX_LINE_SIZE, stdin)) {
- l = trim_ws(line);
- if(*l) {
- run_line(s, l, format);
- }
- printf(NAME "> ");
- fflush(stdout); /* prompt */
- };
- free(line);
- line = 0;
- #endif /* USE_READLINE */
- end:
- /* normal exit */
- if(line)
- free(line);
- if(format)
- free(format);
- if(rpc_array)
- free_rpc_array(rpc_array, rpc_no);
- #ifdef USE_CFG_VARS
- if(cfg_grp_lst)
- free_cfg_grp_lst();
- if(cfg_vars_array) {
- free_rpc_array(cfg_vars_array, cfg_vars_no);
- cfg_vars_array = 0;
- cfg_vars_no = 0;
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- if(cnt_grp_lst)
- free_cnt_grp_lst();
- if(cnt_grps_array) {
- free_rpc_array(cnt_grps_array, cnt_grps_no);
- cnt_grps_array = 0;
- cnt_grps_no = 0;
- }
- #endif /* USE_COUNTERS */
- cleanup();
- exit(0);
- error:
- if(line)
- free(line);
- if(format)
- free(format);
- if(rpc_array)
- free_rpc_array(rpc_array, rpc_no);
- #ifdef USE_CFG_VARS
- if(cfg_grp_lst)
- free_cfg_grp_lst();
- if(cfg_vars_array) {
- free_rpc_array(cfg_vars_array, cfg_vars_no);
- cfg_vars_array = 0;
- cfg_vars_no = 0;
- }
- #endif /* USE_CFG_VARS */
- #ifdef USE_COUNTERS
- if(cnt_grp_lst)
- free_cnt_grp_lst();
- if(cnt_grps_array) {
- free_rpc_array(cnt_grps_array, cnt_grps_no);
- cnt_grps_array = 0;
- cnt_grps_no = 0;
- }
- #endif /* USE_COUNTERS */
- cleanup();
- exit(-1);
- }
|